1. 前言
在C++中,我们经常会使用常量或者表达式,而其中涉及到的常量包括了const和constexpr。但是,要清楚它们之间的区别却并不容易,所以在这篇文章中,我们将重点讨论C++中的常量表达式、const和constexpr的区别。
2. C++常量表达式
2.1 常量表达式的定义
C++11引入了常量表达式(constant expression)的概念,它用于表示在编译期间可以被求值的表达式。在C++中,常量表达式的定义并不是很明确,一般地认为一个表达式属于常量表达式需要满足以下条件:
它只包含了编译期间能够处理的操作符和函数
在表达式求值时,其结果必须在编译期间就可以求得
它的类型必须属于整数类型、枚举类型、浮点类型、指针类型或引用类型
下面举几个常量表达式的例子:
constexpr int n1 = 10;
constexpr int n2 = n1 * 2;
enum class Color { RED, BLUE, GREEN };
constexpr Color c = Color::RED;
constexpr double pi = 3.1415926;
constexpr int* p = nullptr;
int arr[n1]; // 正确
int arr2[n2]; // 正确
Color arr3[c]; // 正确
int arr4[pi * 10]; // 错误
2.2 常量表达式的优点
常量表达式的存在使得编译器在编译期间就可以确定某个变量的值,这在程序的优化和性能方面有着非常重要的意义。例如在下面的代码中:
const int n = 100;
int arr[n];
虽然我们将n定义为了const常量,但是在定义数组时,编译器并不能确定n的值,因此需要在运行期间分配内存。但是,如果我们将n定义为常量表达式的形式,编译器就可以在编译期间就知道数组大小,从而在程序执行时不需要再进行内存分配操作,从而提高程序的运行效率。
3. const关键字
3.1 const的作用
在C++中,const关键字可以用来声明一个常量,即变量的值不能被改变:
const int n = 100;
n = 200; // 错误
const还可以修饰函数的参数和返回值,用于限定参数和返回值的只读属性。例如:
int add(const int& a, const int& b) {
return a + b;
}
const int sum = add(1, 2);
在上面的例子中,我们用const修饰了函数的参数,表示在函数内部不会改变参数的值。同时,我们也将函数的返回值声明为const,表示函数返回的值不能被修改。
3.2 const并非常量表达式
虽然const可以用来声明一个常量,但是const并不等同于常量表达式。const定义的常量虽然不能被修改,但是在编译期间并不能确定它的值,因此不能用来定义数组的大小等需要确定值的场合。例如:
const int n = 100;
int arr[n]; // 错误
上面的例子中,我们将n定义为了const常量,但是在定义数组时,编译器并不能确定n的值,因此需要在运行期间分配内存。
4. constexpr关键字
4.1 constexpr的作用
C++11引入了constexpr关键字,用于声明常量表达式。constexpr声明的变量可以被视为编译期间就可以被确定的常量,因此可以用在需要确定值的场合,例如定义数组的大小等。
constexpr int n = 100;
int arr[n]; // 正确
4.2 constexpr函数
除了用来声明常量表达式外,constexpr还可以用来修饰函数,表示该函数返回的值是常量表达式。常量表达式函数可以在编译期间就被计算出来,因此可以用来定义constexpr变量、数组的大小等。例如:
constexpr int fib(int n) {
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
}
constexpr int f = fib(10); // 在编译期间计算fib(10)的值
int arr[f]; // 正确
需要注意的是,constexpr函数的参数和返回值必须都是常量表达式类型。因此,下面的例子是错误的:
int add(const int& a, const int& b) {
return a + b;
}
constexpr int sum = add(1, 2); // 错误
由于add函数的参数不是常量表达式类型,因此不能在编译期间就计算出sum的值。
5. 总结
C++中的常量表达式、const和constexpr虽然都与常量有关,但是它们之间的区别还是很大的。常量表达式用于定义编译期间可以被求值的表达式,可以用来定义constexpr变量、数组的大小等。const关键字可以用来声明常量,但是不能用于定义数组的大小等需要确定值的场合。constexpr关键字除了用于声明常量表达式外,还可以用于修饰函数,表示函数返回的值是常量表达式。