1. const 的局限性
const 修饰变量代表这个变量不能被修改,但它不一定是编译期常量,也就是说它不能区分编译期常量和运行期常量,它的值完全可以运行时才确定。
#include <iostream>
int get_runtime_val()
{
return 666;
}
int main()
{
const int c1 = 10;
const int c2 = get_runtime_val();
return 0;
}
- c1是字面量初始化,编译器可以识别为常亮,只读,允许运行时初始化。
- c2是运行调用get_runtime_val()得到,仅仅是运行时只读变量,不能用做数组大小、模板参数。
const修饰只读,运行时可以初始化;constexpr修饰编译期可求值,要求编译期阶段就能算出来。
2. constexpr修饰变量(c++11)
被constexpr修饰的变量,必须编译期就能得到结果。
其语法格式:
constexpr 类型 变量名 = 常量表达式;
constexpr int A = 20;
constexpr int B = A * 3 + 5;
int arr[A]; // 标准C++允许,编译期常量
int arr2[B]; //
// constexpr int C = get_num(); // 报错,get_num运行时调用,不是常量表达式
- constexpr变量初始化表达式,必须是常量表达式
- 不允许运行时函数返回初始化
- constexpr变量隐式带上const属性,不能修改
![image]()
3. constexpr 修饰函数(C++11 ~ C++17 变化)
C++11 constexpr 函数限制非常严格
- 函数里面只能有一条 return 语句;
- 不能有局部变量;
- 不能循环、if;
- 参数、返回值必须是字面值类型;
// C++11合法constexpr函数
constexpr int calc(int x)
{
return x * x + 2;
}
int main()
{
constexpr int res = calc(10); // 编译期计算 res = 102
int arr[res]; // 数组大小
int a = 5;
int res2 = calc(a); // 也可以运行时调用,普通函数使用
return 0;
}
constexpr 函数有双重能力:
- 如果传入常量表达式实参,则在编译期计算;
- 如果传入普通运行时变量,退化成普通函数,运行时执行。
C++14 放松 constexpr 函数限制
C++14:constexpr 函数允许局部变量、循环、if 分支,函数体内可以有多条语句。
// C++14 可以写循环
constexpr int factorial(int n)
{
int ret = 1;
for(int i = 2; i <= n; ++i)
{
ret *= i;
}
return ret;
}
int main()
{
constexpr int f5 = factorial(5); // 编译期算出120
return 0;
}
C++17:constexpr if(编译期分支)
template<typename T>
void func(T t)
{
if constexpr(sizeof(T) == 4)
{
// 仅int等4字节类型编译这一段代码
}
else
{
// 其他类型编译这一段
}
}
4. constexpr 修饰构造函数(常量表达式对象)
C++11 允许constexpr构造函数,可以在编译期构造对象。
要求:构造函数体内不能有复杂逻辑,成员全部常量初始化。
struct Point
{
int x;
int y;
// constexpr构造函数
constexpr Point(int a, int b) : x(a), y(b)
{}
};
int main()
{
// 编译期就构造完成对象,不占用运行时
constexpr Point p{10,20};
static_assert(p.x == 10, "error"); //编译期断言,条件不满足直接编译报错,运行时无开销。
return 0;
}
5. constexpr 与 const 总结
| 特性 | const | constexpr |
|---|---|---|
| 主要作用 | 只读保护 | 编译期求值 |
| 变量初始化 | 可以运行时初始化 | 必须常量表达式 |
| 修饰函数 | 不能修饰函数(C++ 前) | C++11 起支持编译期函数 |
| 数组大小 | 不一定可用 | 可以做编译期数组大小 |
| 对象 | 可以修饰运行时对象 | 可以编译期构造对象 |
| 是否隐式带 const | 是 | 是 |

浙公网安备 33010602011771号