简介
constexpr 为 C++11 提供的说明符,目的是将运算尽量放在编译阶段,而不是运行阶段
声明对象或非静态成员函数 (C++14 前)
时使用 constexpr 说明符则同时蕴含 const
声明函数或静态成员变量 (C++17 起)
时使用 constexpr 说明符则同时蕴含 inline
如果一个函数或函数模板的某个声明拥有 constexpr 说明符,则其所有声明都必须含有该说明符
constexpr变量
要求
一句话而言:声明为constexpr的变量一定是常量,而且必须用常量表达式初始化
详解
1. 声明
声明 constexpr 变量时用到的类型被称为字面值类型,声明为 constexpr 的变量一定是一个 const 变量,而且必须用常量表达式初始化
1 | constexpr int num = 20; //num为常量表达式 |
2. constexpr指针
需要注意的是,与 const 修饰指针不同,一个指针被定义为 constexpr ,关键字仅对指针有效,与指针所指的对象无关
constexpr 指针的初始值受到严格的限制。一个 constexpr 指针的初始值必须是 nullptr 或者 0 ,或者是像先前说的一样是存储某个固定地址的对象
1 | const int* p = nullptr; //p为指向整形常量的指针 |
constexpr函数
要求
一句话而言:函数的返回类型和所有形参必须为字面值类型(声明 constexpr 变量时用到的类型),且函数体中必须有且只有一条 return 语句,但不产生实际代码的语句可以在 constexpr 函数中使用(using,static_assert,typedef, …)
详解
1. 实参传入
当 constexpr 所修饰的函数实参是在运行时才能传入,那么这个 constexpr 是无效的,相当于普通函数
2. 有关返回值
我们允许 constexpr 函数的返回值并非一个常量,而可以是另一个 constexpr 函数的返回值,即为字面值类型即可
使用这个特性,有一些递归函数可以通过 O(n) 的复杂度完成
1 | //在开启内联优化的编译器上,使用 constexpr 修饰函数和不适用完成斐波拉契函数的递归实现区别 |
反汇编
1 | ... |
不难看出,res1 的值是直接通过已经计算出来的值赋的,而 res2 的则是通过调用函数
if constexpr
C++17中引入了一个新用法:
1 | if constexpr(condition) |
condition所需满足以下两个条件:
- 在编译期就能算出true或者false。
- 或是通过类型转换为true或者false。
两个条件只要成立,编译期便会照着是否满足if中条件来选择编译对应块中的内容,可以粗略的认为另一个板块被摒弃了。