constexpr的语义是“常量表达式”,也就是在编译期可求值的表达式。
constexpr所修饰的变量一定是编译期可求值的。
constexpr修饰函数,至少对一组实参,可以在编译期间产生编译期常数。
constexpr int Inc(int i) {
return i + 1;
}
constexpr int a = Inc(1); // ok
constexpr int b = a * 2 + 1; // ok
constexpr int c = Inc(cin.get()); // error
编译期计算
使用constexpr实现阶乘函数。
#include <stdio.h>
constexpr int factorial(int n)
{
if (n == 0) {
return 1;
} else {
return n * factorial(n - 1);
}
}
int main()
{
constexpr int n = factorial(10);
printf("%d\n", n);
}
使用https://godbolt.org/ 查看上述代码的汇编代码,常量3628800即为factorial(10)在编译时就计算出的结果。
main: # @main
push rax
mov edi, offset .L.str
mov esi, 3628800
xor eax, eax
call printf
xor eax, eax
pop rcx
ret
.L.str:
.asciz "%d\n"
constexpr修饰类的构造函数(构造函数内不能有动态内存分配),该构造函数的参数都是constexpr,该对象也就是constexpr对象(成员变量的初始化都放到初始化列表中)。
struct A {
constexpr A(int x, int y): X(x), Y(y) {}
int X, Y;
};
constexpr A a(1, 2);
从c++14开始,很多标准类的构造函数和成员函数被标记为constexpr,以便在编译期使用。如:pair, tuple, string_view, optional等。
#include <array>
#include <iostream>
#include <memory>
#include <string_view>
using namespace std;
int main()
{
constexpr string_view sv{"hi"};
constexpr pair pr{sv[0], sv[1]};
constexpr array a{pr.first, pr.second};
constexpr int n1 = a[0];
constexpr int n2 = a[1];
cout << "n1 = " << n1 <<endl;
cout << "n2 = " << n2 <<endl;
}
运行结果:
n1 = 104
n2 = 105
constexpr优点
- 编译器对constexpr的代码优化,将用到的constexpr表达式都直接替换成最终结果。
- 相比宏来说,constexpr没有额外的开销,但更安全可靠。