如何强制C++的constexpr函数仅在编译期运行?
如何强制constexpr函数仅在编译期执行?
问题背景
constexpr函数可以在编译期或运行期执行,有没有办法强制它只能在编译期执行?以下是遇到问题的示例代码及编译错误:
示例代码1
constexpr int BUILD(int i) { static_assert(0 == i); i++; return i; } enum Events { FIRST = BUILD(0) };
编译错误
Error[Pe028]: expression must have a constant value
补充示例(说明需求场景)
constexpr int BUILD(int a, int b, int c, int d) { static_assert(a < b); static_assert(b < c); static_assert(c < d); static_assert(d < 10); return a+b+c+d; } enum Events { FIRST = BUILD(0, 4, 6, 9), // 手动定义参数 SECOND = BUILD(2, 3, 7, 8), THIRD = BUILD(0, 1, 2, 3), };
解决方案
方案1:使用C++20的consteval关键字
C++20引入了consteval关键字,用它声明的函数必须在编译期求值,运行期调用会直接报错。修改示例代码如下:
consteval int BUILD(int i) { static_assert(0 == i); i++; return i; } enum Events { FIRST = BUILD(0) };
对于多参数的补充示例,同样替换constexpr为consteval即可:
consteval int BUILD(int a, int b, int c, int d) { static_assert(a < b); static_assert(b < c); static_assert(c < d); static_assert(d < 10); return a+b+c+d; } enum Events { FIRST = BUILD(0, 4, 6, 9), SECOND = BUILD(2, 3, 7, 8), THIRD = BUILD(0, 1, 2, 3), };
方案2:兼容C++11/14/17的模板参数方案
如果需要兼容旧标准,可以将函数参数改为模板非类型参数,这样参数本身就是编译期常量,强制函数只能在编译期执行:
单参数示例修改:
template<int i> constexpr int BUILD() { static_assert(0 == i); return i + 1; } enum Events { FIRST = BUILD<0>() };
多参数示例修改:
template<int a, int b, int c, int d> constexpr int BUILD() { static_assert(a < b); static_assert(b < c); static_assert(c < d); static_assert(d < 10); return a + b + c + d; } enum Events { FIRST = BUILD<0, 4, 6, 9>(), SECOND = BUILD<2, 3, 7, 8>(), THIRD = BUILD<0, 1, 2, 3>(), };
原代码报错原因
在C++20之前,constexpr函数中的static_assert不能依赖普通函数形参——因为编译器无法保证调用时传入的是常量表达式,static_assert作为编译期断言,无法对运行期可能变化的参数进行检查。而consteval强制所有实参必须是常量表达式,模板非类型参数本身就是编译期常量,这两种方式都能让static_assert正常生效,同时强制函数仅在编译期执行。
内容的提问来源于stack exchange,提问作者Ronen333
相关产品推荐
相关产品推荐

