为什么引入`constexpr`和`consteval`?
确保表达式可以在编译时求值。将昂贵的计算从运行时转移到编译时以显著提高性能。
例子1 使用const
或constexpr
上面的例子将编译出错,提示:Non-type template argument is not a constant expression
int value{3};
在运行时求值,而Resource<>
的非类型模板参数SomeInt
需要在编译时求值,在编译时value
的值还不知道,所以出错。
解决的办法就是让value
在编译时求值。
可使用const
或constexpr
关键字。
const
为什么也可用?const
表达式在运行时求值,但const
变量也可以作为编译时常量,只要它是一个常量表达式。不过,const
的业务太繁忙了,如果要确保在编译时求值,还是用constexpr
吧。
例子2 constexpr
函数
看一个只能用constexpr
、不能用const
的例子。
函数get_int()
被标记为constexpr
,编译器确保在编译时对函数求值,所以函数返回值可用于初始化一个 constexpr
变量。
当然,constexpr
函数的返回值也可作为模板的非类型模板参数。
例子3 consteval
函数
函数被标记为constexpr
,并不意味着该函数只能在编译时使用,运行时也可使用。如下:
函数add()
是一个constexpr
函数,但是在上面的例子中是在运行时求值。
如果想确保一个函数只能在编译时使用、不能在运行时使用,要是在运行时使用了就无法编译通过,怎么做到?
在函数声明中使用consteval
关键字。
如把上面add()
函数标记为consteval
,则上面的程序会编译出错:error: call to consteval function ‘add(get_number(), get_number())’ is not a constant expression
例子4 运行时使用consteval
函数?
既然consteval
函数只能在编译时使用,无法在运行时使用,那为什么下面这个程序能编译成功呢?
在语句std::cout << add(1, 2) << std::endl;
中,add(1, 2)
的确是在编译时计算,结果为3
,在代码中add(1, 2)
被3
代替。在运行时,main()
中的语句看起来是std::cout << 3 << std::endl;
,就好像add(1, 2)
压根不存在。
那为什么std::cout << add(get_number(), get_number()) << std::endl;
会编译出错?因为get_number()
的值是在运行时计算,在编译时add()
无法求值,所以会出错。