You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何该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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 00:22:50