constexpr 限制放宽

constexpr 限制放宽
苏丙榅1. constexpr 概述
constexpr(常量表达式)是 C++11 引入的关键字,用于指定值或函数可以在编译时计算,是编译时计算的核心特性。其设计目标主要有以下几点:
- 编译时计算:将运行时计算转移到编译时
- 类型安全:编译时进行类型检查
- 性能优化:消除运行时开销
- 泛型编程:增强模板元编程能力
1 | // 编译时常量 |
关于constexpr的使用和const是类似的,下面的表格中将二者的特性进行是对比:
| 特性 | const |
constexpr |
|---|---|---|
| 主要含义 | 只读,不可修改 | 编译时常量 |
| 初始化时机 | 运行时或编译时 | 必须编译时 |
| 能否修改 | 初始化后不可修改 | 初始化后不可修改 |
| 作用域 | 类型修饰符 | 类型修饰符 + 函数修饰符 |
| C++版本 | C++98 | C++11+ |
const 初始化时机不一定是编译时
1
const T x = expr;
- 如果
expr是常量表达式,则x是编译时常量 - 否则,
x是运行时常量(只读变量)
- 如果
constexpr 初始化时机一定是编译时
1
constexpr T x = expr; // expr必须是常量表达式
expr必须在编译时可求值- 否则编译失败
constexpr 隐含 const 属性
1
2constexpr int a = 10;
a = 20; // ❌ 编译错误:constexpr变量也是const
最后给大家列举一些需要编译时常量的场景:
数组大小:
int array[N];模板非类型参数:
template<int N>case标签:
case VALUE:位域宽度(指定一个整型成员使用多少个比特(bit)来存储数据):
unsigned int x : WIDTH;枚举值初始化:
enum E { val = N };对齐说明符:
alignas(N)-alignas(N)是C++11引入的对齐说明符,用于显式指定变量、类、结构体或数组在内存中的对齐方式。语法格式如下:1
2
3
4
5
6
7
8
9
10
11
12
13// 1. 直接对齐数值
alignas(alignment) type variable;
// 2. 使用类型作为对齐参考
alignas(type) type variable;
// 3. 多种写法
alignas(16) int a; // 16字节对齐
alignas(8) int b; // 8字节对齐
alignas(4) int c; // 4字节对齐
alignas(double) char buffer[1024]; // 按double类型的对齐要求对齐
alignas(16) struct MyStruct { ... }; // 结构体对齐, 结构体总大小将是16的倍数
alignas(32) int arr[10]; // 数组对齐
2. constexpr 在 C++14 中改进
C++14 对 constexpr 做了重大改进,显著放宽了限制,使其在实际编程中更加实用。以下是详细说明:
2.1 放宽函数体内的限制
C++11 中只能有一条 return 语句,不能有局部变量、循环、分支等
1
2
3
4constexpr int factorial(int n)
{
return n <= 1 ? 1 : n * factorial(n - 1);
}C++14 放宽了限制,允许循环、允许使用局部变量并修改、允许使用 if-else等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25constexpr int factorial(int n)
{
// C++14: 允许局部变量
int result = 1;
// C++14: 允许循环
for (int i = 1; i <= n; ++i)
{
result *= i;
}
return result;
}
constexpr int abs_value(int x)
{
// C++14: 允许 if-else
if (x < 0)
{
return -x;
}
else
{
return x;
}
}
2.2 constexpr 成员函数不再隐式为 const
在 C++11 中,被constexpr修饰的类成员函数会隐式成为 const 函数(常量成员函数),不能修改成员变量。
1 | class Widget |
C++14中,constexpr修饰的类成员函数体内部可以修改类成员的值。
1 | class Point |
2.3 允许 void 类型的 constexpr 函数
在C++14中,constexpr 函数可以返回 void,在 C++11 中该语法是不允许的。
1 | constexpr void swap(int& a, int& b) |
2.4 类的构造函数
在 C++11 中,constexpr 构造函数必须是空的,只能通过初始化列表初始化所有成员:
1 | // C++11 的 constexpr 构造函数 |
C++14 允许 constexpr 构造函数有函数体,可以包含控制流语句:
1 | // C++14 的 constexpr 构造函数 |
根据上文对讲解,我们可以对 constexpr 在 C++11 与 C++14 中的特性做如下总结:
| 特性 | C++11 | C++14 |
|---|---|---|
| 构造函数体 | 必须为空 | 可以有任意语句 |
| 局部变量 | ❌ 不允许 | ✅ 允许 |
| 控制流语句 | ❌ 不允许 | ✅ 允许 |
| 函数调用 | ❌ 不允许 | ✅ 允许(调用 constexpr 函数) |
| 循环 | ❌ 不允许 | ✅ 允许 |
| 修改类成员 | 只能在初始化列表 | 可以在函数体内 |
C++14 对 constexpr 的改进使得编译时编程成为 C++ 的强大特性,为模板元编程和编译时计算提供了更自然的语法。












