在C++中,常量表达式是指在编译期间就能计算出其值的表达式,并且该值在程序运行过程中不会改变,编译器可以在编译时就确定它的值。并且可以在需要常量
值的上下文中使用。
下面的几个例子都是常量表达式:
1.整型字面值,如10、20等,这些都是常量表达式,因为它们在编译时就已经确定了值。
2.算术表达式,只要其中的操作数都是常量表达式,整个算术表达式也是常量表达式。例如2 + 3 * 4,根据运算符优先级,先计算3 * 4 = 12,然后2+12 = 14,这
个计算过程在编译阶段就可以完成,所以它是常量表达式。
3.枚举类型的值 例如,Color::Green是一个常量表达式,它的值是2在编译时就已经确定。
enum class Color { Red, Green, Blue };
Color c = Color::Green;
4.字面值常量,用常量表达式初始化的常量对象等都是常量表达式。
字面值常量: 直接在代码中写出的常量值。它是一种基本的数据形式,用来表示固定的值。
例如:
整数字面值:如1,0,-10等
浮点数字面值:例如3.14,2.718
字符字面值:用单引号括起来的字符,如'a','0','\n'(换行符)
字符串字面值:用双引号括起来的字符序列,如"Hello","123"。
布尔字面值:true和false
常量表达式初始化的常量对象都是常量表达式的原因:这个初始化过程在编译阶段就可以完成
const int a = 10;
const int b = a + 5;
a是用常量表达式10初始化的常量对象。而b是用a + 5初始化的,因为a是常量表达式,5也是常量表达式,所以a + 5这个算术表达式在编译阶段可以计算出结果,因此b也是常量表达式。编译器可以在编译程序时就确定b的值为15,并且这个值在程序运行期间不会改变。这符合常量表达式在编译期间就能确定值且值固定不变的特点。
什么场景下使用常量表达式:
1.定义数组大小:定义数组时,数组的大小必须是一个常量表达式,因为数组在内存中的空间是在编译时就分配好的
const int N = 10;
int ptr[N];
2.作为模板参数: 模板参数可以是常量表达式。模板是一种代码生成机制,在编译时根据模板参数生成具体的代码。
例如,定义一个简单的模板函数来计算两个数的乘积:这里3和4作为常量表达式传递给模板参数num1和num2,编译器在编译时就可以根据这些参数计算出result的值为12。这种用法可以在编译时进行一些计算,提高程序运行时的效率,并且可以生成更加通用的代码。
template<int num1, int num2>
constexpr int multiply() {return num1 * num2;
}
//调用
constexpr int result = multiply<3, 4>();
3.初始化常量对象
a.基本数据类型常量对象:
#include <iostream>
using namespace std;
int main() {// 使用整数常量表达式初始化常量对象constexpr int const_int = 10; // 使用字符常量表达式初始化常量对象constexpr char const_char = 'A'; // 使用布尔常量表达式初始化常量对象constexpr bool const_bool = true; cout << "const_int: " << const_int << endl;cout << "const_char: " << const_char << endl;cout << "const_bool: " << const_bool << endl;return 0;
}
b.使用constexpr函数的结果初始化常量对象
例如下面 定义了一个constexpr函数square,它可以在编译时计算出结果。然后通过调用这个函数并将其结果作为常量表达式来初始化常量对象const_square。
#include <iostream>
using namespace std;
// constexpr函数,用于计算平方
constexpr int square(int x) {return x * x;
}
int main()
{// 使用constexpr函数的结果作为常量表达式来初始化常量对象constexpr int s= square(5); cout << "s的值: " << s << endl;return 0;
}
4.枚举常量的初始化: 枚举类型是一种用户自定义的数据类型,用于定义一组命名的常量。在初始化枚举常量时,可以使用常量表达式。
例如,定义一个表示颜色的枚举类型:这里RED、GREEN和BLUE的初始值是常量表达式(0,1和2)。这种用法可以让枚举常量在编译时就有确定的值,方便在程序中进行比较和使用。
enum class Color {RED = 0,GREEN = 1,BLUE = 2 * 1
};
5.开关语句(switch)中的常量表达式
在switch语句中,case标签后面的值必须是常量表达式。这是为了让编译器在编译时就能确定跳转的目标位置。
int main() {int choice = 2;switch (choice) {case 1:cout << "星期一" << endl;break;case 2:cout << "星期二" << endl;break;default:cout << "未定义" << endl;break;}return 0;
}
如何判断一个表达式是否是常量表达式
1.常量和字面量
像整数常量(如42),字符常量(如'A'),字符串字面量(如"Hello")等都是常量表达式。这些值在编译时就已经确定,并且不会改变。
2.用const修饰的变量且有初始值
如果一个变量被const修饰,并且它的初始值是一个常量表达式,那么这个变量也可以看作是常量表达式。
例如:这里a在编译时就被初始化为5,并且后续不能被修改,所以它是常量表达式。
const int a = 5; // 'a'是常量表达式
注意,如果const变量没有初始值,或者初始值不是常量表达式,那么它不是常量表达式。例如:
const int b; //不是常量表达式,没有初始值
int c = 3;
const int d = c; // 不是常量表达式,初始值依赖于运行时的值(因为赋值运算在运行时才能实现)
3. constexpr 关键字
可以使用constexpr关键字来声明一个函数或者变量是常量表达式。对于函数它要求函数体足够简单,能够在编译时计算出结果。
例如:这个square函数是一个常量表达式函数,因为它的计算逻辑简单,编译器可以在编译阶段计算出square函数的结果。
constexpr int square(int x) {return x * x;
}
int main() {constexpr int result = square(3); // 可以在编译时计算出square(3)的值为9return 0;
}
对于变量,constexpr变量必须用常量表达式初始化。
constexpr int e = 2 + 3; // 'e'是常量表达式,初始值是常量表达式'2 + 3'