为何该consteval函数无法常量求值?局部变量传参却可行
consteval函数常量求值失败的原因解析
问题场景
调用consteval修饰的can_serialise函数时,传入*this和t会触发"表达式未求值为常量"的错误,但传入局部变量local_serialiser和&local_t却能正常运行。代码示例:
enum class MySerialisationMode { YES, NO }; template <MySerialisationMode serialisation_mode> struct MySerialiser; struct ClassThatsNotAllowedToAccess{ constexpr ClassThatsNotAllowedToAccess() {} template <MySerialisationMode mode, typename T> consteval bool can_serialise(MySerialiser<mode>& serialiser, T* t) const { return true; } }; template <MySerialisationMode serialisation_mode> struct MySerialiser { template <typename T> void serialise(T* t) { constexpr ClassThatsNotAllowedToAccess c1; T local_t; MySerialiser<serialisation_mode> local_serialiser; //constexpr bool canSerialise = c1.can_serialise<serialisation_mode, T>(*this, t); // 报错:表达式未求值为常量 constexpr bool canSerialise = c1.can_serialise<serialisation_mode, T>(local_serialiser, &local_t); // 正常运行 } }; struct MyFoo2 {}; int main(int argc, char* argv[]) { MyFoo2 myfoo2; MySerialiser<MySerialisationMode::YES> serialiser; serialiser.serialise(&myfoo2); }
核心原因
consteval函数要求所有实参必须是常量表达式,或者是在当前常量求值上下文内创建的实体,两者的参数差异刚好命中这一规则:
关于
*this:*this指向的是main函数中创建的MySerialiser实例,属于运行时分配的实体,并非在常量求值上下文(即constexpr bool canSerialise的初始化过程)内创建,无法满足consteval函数对引用参数的常量性要求——引用参数必须绑定到常量表达式允许的对象(如constexpr变量、常量求值期间创建的局部变量)。关于
t:t指向的是main函数中的myfoo2对象,该对象的地址不是常量表达式。C++标准规定,常量表达式中的指针只能指向静态存储期对象、字符串字面量,或者常量求值期间创建的对象的地址。而&local_t是在常量求值过程中创建的局部变量的地址,完全符合规则。局部变量
local_serialiser和local_t:两者都是在constexpr bool canSerialise的常量求值上下文内部声明的局部变量,它们的引用和地址天然满足consteval函数的参数要求,因此调用可以成功。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

