能否调用前向声明的constexpr函数为constexpr变量赋值?
C++ constexpr初始化报"expression did not evaluate to a constant"规则解析
问题场景
编写C++代码时触发编译错误,错误信息为expression did not evaluate to a constant,复现代码如下:
constexpr uint64 createDynamicPipelineStateMask(); static inline constexpr uint64 dynamic_state_mask = createDynamicPipelineStateMask(); struct CullMode { static constexpr inline bool bIsDynamicState = false; static constexpr inline uint64 mask = 0; }; constexpr uint64 createDynamicPipelineStateMask() { uint64 dynamic_mask = 0; if constexpr (CullMode::bIsDynamicState) dynamic_mask |= CullMode::mask; return dynamic_mask; }
已知将constexpr变量dynamic_state_mask的定义移动到createDynamicPipelineStateMask()函数定义之后即可修复问题,但对规则存在疑问:已知constexpr函数的完整定义需要在编译阶段对编译器可见(不能交由链接器处理),但上述代码中函数定义明明和变量初始化在同一个编译单元、只是位置靠下,为什么仍然无法正常编译?
规则说明
- 编译器解析C++源码是严格从上到下逐行处理的,所有符号的可见性只看当前解析位置之前已经出现的声明/定义,不会提前读取后面位置的代码内容。
- 普通函数的调用只要求调用点能看到函数前置声明即可:编译阶段仅校验函数签名匹配,函数实体的地址解析会留给链接阶段处理,因此普通函数的调用点可以放在同编译单元内函数定义的前面。
- 但
constexpr变量的初始化是编译期必须完成求值的常量表达式上下文,在这个上下文里调用constexpr函数时,要求调用点必须已经能看到该函数的完整定义,不能只有前置声明:编译器需要拿到完整的函数体才能执行编译期计算,不可能等链接阶段再处理,也不会向后查找同文件里的函数定义。 - 上述代码中,处理到
dynamic_state_mask的初始化语句时,编译器只看到了createDynamicPipelineStateMask()的前置声明,完全没接触到后面的函数实现,自然无法完成编译期求值,直接抛出常量表达式求值失败的错误。 - 额外注意:修复时除了要把
createDynamicPipelineStateMask()的定义放到dynamic_state_mask初始化语句之前,还要保证CullMode结构体的定义也放在函数定义之前——否则函数体内引用CullMode::bIsDynamicState和CullMode::mask时,同样会因为编译器还没看到CullMode的完整定义而报错。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

