命名空间
变体
操作

常量表达式

来自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17*)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

定义一个可在编译时求值的表达式

此类表达式可用作非类型模板实参、数组大小以及其他需要常量表达式的上下文中,例如:

int n = 1;
std::array<int, n> a1;  // Error: “n” is not a constant expression
const int cn = 2;
std::array<int, cn> a2; // OK: “cn” is a constant expression

目录

[编辑] 定义

属于下列任何常量表达式类别的表达式是常量表达式

C++98 常量表达式类别

整型常量表达式 (C++98)

在以下位置,C++ 要求表达式求值为整型或枚举常量

满足以下所有条件的表达式是整型常量表达式 

  • 它仅涉及以下实体
  • 算术类型的字面量
  • 枚举项
  • 满足以下所有条件的变量或静态数据成员
  • 它们是 const 限定的。
  • 它们不是 volatile 限定的。
  • 它们的类型为整型或枚举类型。
  • 它们使用常量表达式初始化。
  • 它不使用任何浮点字面量,除非它们被显式转换为整型或枚举类型。
  • 它不对非整型和非枚举类型应用任何转换。
  • 它不使用以下任何实体,除非在 sizeof 的操作数中
  • 函数
  • 类对象
  • 指针
  • 引用
  • 赋值运算符
  • 自增运算符
  • 自减运算符
  • 函数调用运算符
  • 逗号运算符

其他常量表达式类别

其他表达式仅在常量初始化的目的下被视为常量表达式。此类常量表达式必须是以下表达式之一

  • 求值为空指针值的表达式
  • 求值为空成员指针值的表达式
  • 算术常量表达式
  • 地址常量表达式
  • 引用常量表达式
  • 完整对象类型的地址常量表达式,加上或减去整型常量表达式
  • 成员指针常量表达式

算术常量表达式是满足整型常量表达式要求的表达式,但有以下例外

  • 浮点字面量可以不经显式转换而使用。
  • 可以应用到浮点类型的转换。

地址常量表达式是指针类型的表达式,满足以下所有条件

  • 显式使用取地址运算符
  • 隐式使用指针类型的非类型模板形参
  • 使用数组或函数类型的表达式
  • 表达式不调用任何函数。
  • 表达式使用显式指针转换(除了 dynamic_cast)和以下运算符,但不访问结果对象
  • 下标运算符
  • 间接寻址运算符
  • 取地址运算符
  • 成员访问运算符
  • 如果使用下标运算符,则其操作数之一是整型常量表达式。

引用常量表达式是引用类型的表达式,满足以下所有条件

  • 引用指定静态存储期的对象、引用类型的非类型模板形参或函数。引用不指定非 POD 类类型的成员或基类。
  • 表达式不调用任何函数。
  • 表达式使用显式引用转换(除了 dynamic_cast)和以下运算符,但不访问结果对象
  • 下标运算符
  • 间接寻址运算符
  • 取地址运算符
  • 成员访问运算符
  • 如果使用下标运算符,则其操作数之一是整型常量表达式。

成员指针常量表达式是指针到成员类型的表达式,其中指针通过将取地址运算符应用于限定标识符而创建,可以选择在前面加上显式指针到成员的转换。

(直到 C++11)

以下表达式统称为常量表达式 

  • 具有静态存储期的对象的地址
  • 函数的地址
  • 空指针值
(自 C++11 起)
(直到 C++14)

以下实体是常量表达式的允许结果 

  • 具有静态存储期的临时对象
  • 具有静态存储期的非临时对象,其值满足下列约束
  • 立即 (自 C++20 起)函数

常量表达式是左值核心常量表达式,其引用作为常量表达式的允许结果的实体,或者是纯右值核心常量表达式,其值满足以下约束

  • 如果值是类类型的对象,则引用类型的每个非静态数据成员都引用作为常量表达式的允许结果的实体。
  • 如果值是标量类型的对象,则它不具有不确定值。
  • 如果值是指针类型,则它是以下值之一
  • 具有静态存储期的对象的地址
  • 超出具有静态存储期的对象末尾的地址
  • 一个 非立即(自 C++20 起)函数的地址
  • 空指针值
  • 如果值是指向成员函数的指针类型,则它不指定立即函数。
(自 C++20 起)
  • 如果值是类或数组类型的对象,则每个子对象都满足值的这些约束。
(自 C++14 起)
(直到 C++26)

常量表达式是左值核心常量表达式,其引用对象或非立即函数,或者是纯右值核心常量表达式,其值满足以下约束

(自 C++26 起)

在确定表达式是否为常量表达式时,假定不执行复制消除

常量表达式的 C++98 定义完全在折叠框内。以下描述适用于 C++11 和更高版本的 C++。

[编辑] 字面类型

以下类型统称为字面类型 

(自 C++17 起)
  • 满足以下条件之一的聚合联合类型
  • 它没有变体成员
  • 它至少有一个非 volatile 字面类型的变体成员。
  • 非联合聚合类型,并且其每个匿名联合成员都满足以下条件之一
  • 它没有变体成员。
  • 它至少有一个非 volatile 字面类型的变体成员。
  • 具有至少一个非复制或移动构造函数的 constexpr 构造函数(模板)的类型

只能在常量表达式中创建字面类型的对象。

[编辑] 核心常量表达式

核心常量表达式是任何表达式,其求值不会求值以下任何一种语言构造

语言构造     版本     论文
this 指针,除非在作为表达式一部分求值的 constexpr 函数中,或者在隐式或显式类成员访问表达式中出现时 N2235
控制流,其通过声明具有静态或线程存储期块变量,该变量不是可在常量表达式中使用的 (自 C++23 起) P2242R3
  1. 调用未声明为 constexpr 的函数(或构造函数)的函数调用表达式
    constexpr int n = std::numeric_limits<int>::max(); // OK: max() is constexpr
    constexpr int m = std::time(nullptr); // Error: std::time() is not constexpr
  2. 对已声明但未定义的 constexpr 函数的函数调用
  3. constexpr 函数/构造函数模板实例化,其中实例化未能满足 constexpr 函数/构造函数 要求。
  4. 在动态类型为 constexpr 未知的对象上调用的 constexpr 虚函数的函数调用
  5. 将超出实现定义的限制的表达式
  6. 表达式的求值导致任何形式的核心语言未定义或错误(自 C++26 起)行为,标准属性 标准属性引入的任何潜在未定义行为除外。
    constexpr double d1 = 2.0 / 1.0; // OK
    constexpr double d2 = 2.0 / 0.0; // Error: not defined
    constexpr int n = std::numeric_limits<int>::max() + 1; // Error: overflow
    int x, y, z[30];
    constexpr auto e1 = &y - &x;        // Error: undefined
    constexpr auto e2 = &z[20] - &z[3]; // OK
    constexpr std::bitset<2> a; 
    constexpr bool b = a[2]; // UB, but unspecified if detected
  7. (直到 C++17) lambda 表达式
  8. 左值到右值隐式转换,除非应用于...
    1. 类型为(可能带有 cv 限定的)std::nullptr_t 的左值
    2. 指定可在常量表达式中使用的对象的非 volatile 字面类型左值
      int main()
      {
          const std::size_t tabsize = 50;
          int tab[tabsize]; // OK: tabsize is a constant expression
                            // because tabsize is usable in constant expressions
                            // because it has const-qualified integral type, and
                            // its initializer is a constant initializer
       
          std::size_t n = 50;
          const std::size_t sz = n;
          int tab2[sz]; // Error: sz is not a constant expression
                        // because sz is not usable in constant expressions
                        // because its initializer was not a constant initializer
      }
    3. 引用非 volatile 对象的非 volatile 字面类型左值,该对象的生命周期在此表达式的求值期间开始
  9. 应用于联合或其子对象的非活动成员的左值到右值隐式转换或修改(即使它与活动成员共享公共初始序列)
  10. 值不确定的对象进行左值到右值的隐式转换
  11. 联合的隐式复制/移动构造函数/赋值的调用,其活动成员是可变的(如果有),且生命周期在此表达式的求值之外开始
  12. (直到 C++20) 将更改联合的活动成员的赋值表达式
  13. 指向 void 的指针到对象类型 T* 的指针的转换,除非指针持有空指针值或指向类型类似于 T 的对象(自 C++26 起)
  14. dynamic_cast ,其操作数是引用动态类型为 constexpr 未知的对象的左值(自 C++20 起)
  15. reinterpret_cast
  16. (直到 C++20) 伪析构函数调用
  17. (直到 C++14) 自增或自减运算符
  18. (自 C++14 起) 对象的修改,除非对象具有非 volatile 字面类型,并且其生命周期在此表达式的求值期间开始
    constexpr int incr(int& n)
    {
        return ++n;
    }
     
    constexpr int g(int k)
    {
        constexpr int x = incr(k); // Error: incr(k) is not a core constant
                                   // expression because lifetime of k
                                   // began outside the expression incr(k)
        return x;
    }
     
    constexpr int h(int k)
    {
        int x = incr(k); // OK: x is not required to be initialized
                         // with a core constant expression
        return x;
    }
     
    constexpr int y = h(1); // OK: initializes y with the value 2
                            // h(1) is a core constant expression because
                            // the lifetime of k begins inside the expression h(1)
  19. (自 C++20 起) 析构函数调用或伪析构函数调用,用于生命周期未在此表达式求值期间开始的对象
  20. 应用于多态类型左值的 typeid 表达式,并且该左值引用动态类型为 constexpr 未知的对象(自 C++20 起)
  21. new 表达式,除非满足以下条件之一:(自 C++20 起)
    • 所选的分配函数是可替换的全局分配函数,并且分配的存储在此表达式的求值期间被解除分配。
    (自 C++20 起)
    • 所选的分配函数是非分配形式,具有已分配类型 T,并且 placement 实参满足以下所有条件
    • 它指向
    • 类型类似于 T 的对象(如果 T 不是数组类型),或者
    • 类型类似于 T 的对象的第一个元素(如果 T 是数组类型)。
    • 它指向存储,其持续时间在此表达式的求值期间开始。
    (自 C++26 起)
  22. delete 表达式,除非它解除分配在此表达式的求值期间分配的存储区域(自 C++20 起)
  23. (自 C++20 起) 协程:await 表达式yield 表达式
  24. (自 C++20 起) 三路比较,当结果未指定时
  25. 结果未指定的相等或关系运算符
  26. (直到 C++14) 赋值或复合赋值运算符
  27. (直到 C++26) throw 表达式
  28. (自 C++26 起) 异常对象的构造,除非异常对象及其所有由 std::current_exceptionstd::rethrow_exception 调用创建的隐式副本在此表达式的求值期间被销毁
    constexpr void check(int i)
    {
        if (i < 0)
            throw i;
    }
     
    constexpr bool is_ok(int i)
    {
        try {
            check(i);
        } catch (...) {
            return false;
        }
        return true;
    }
     
    constexpr bool always_throw()
    {
        throw 12;
        return true;
    }
     
    static_assert(is_ok(5)); // OK
    static_assert(!is_ok(-1)); // OK since C++26
    static_assert(always_throw()); // Error: uncaught exception
  29. asm 声明
  30. va_arg 的调用
  31. goto 语句
  32. dynamic_casttypeid 表达式new 表达式(自 C++26 起),其将抛出异常,其中异常类型的定义不可达(自 C++26 起)
  33. 在 lambda 表达式内部,对 this 或在 lambda 外部定义的变量的引用,如果该引用将是 odr-use
    void g()
    {
        const int n = 0;
     
        constexpr int j = *&n; // OK: outside of a lambda-expression
     
        [=]
        {
            constexpr int i = n;   // OK: 'n' is not odr-used and not captured here.
            constexpr int j = *&n; // Ill-formed: '&n' would be an odr-use of 'n'.
        };
    }

    请注意,如果 ODR 使用发生在对闭包的函数调用中,则它不引用 this 或封闭变量,因为它访问的是闭包的数据成员

    // OK: 'v' & 'm' are odr-used but do not occur in a constant-expression
    // within the nested lambda
    auto monad = [](auto v){ return [=]{ return v; }; };
    auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; };
     
    // OK to have captures to automatic objects created during constant expression evaluation.
    static_assert(bind(monad(2))(monad)() == monad(2)());
    (自 C++17 起)

[编辑] 额外要求

即使表达式 E 不求值上述任何内容,如果求值 E 将导致运行时未定义行为,则是否 E 是核心常量表达式是实现定义的。

即使表达式 E 不求值上述任何内容,如果求值 E 将求值以下任何内容,则是否 E 是核心常量表达式是未指定的

为了确定表达式是否为核心常量表达式,如果 T 是字面类型,则忽略 std::allocator<T> 的成员函数体的求值。

为了确定表达式是否为核心常量表达式,联合的平凡复制/移动构造函数或复制/移动赋值运算符的调用的求值被视为复制/移动联合的活动成员(如果有)。

为了确定表达式是否为核心常量表达式,命名结构化绑定 bd 的标识符表达式的求值具有以下语义

  • 如果 bd 是引用绑定到发明的引用 ref 的对象的左值,则行为就好像提到了 ref
  • 否则,如果 bd 命名数组元素,则行为就像求值 e[i],其中 e 是从结构化绑定声明的初始化器初始化的变量的名称,而 ibd 引用的元素的索引。
  • 否则,如果 bd 命名类成员,则行为就像求值 e.m,其中 e 是从结构化绑定声明的初始化器初始化的变量的名称,而 mbd 引用的成员的名称。
(自 C++26 起)

在作为核心常量表达式求值表达式期间,所有标识符表达式和 *this 的使用,其引用生命周期在表达式求值之外开始的对象或引用,都被视为引用该对象的特定实例,该对象的生命周期以及所有子对象(包括所有联合成员)的生命周期都包含整个常量求值。

  • 对于这样的对象,它不是可在常量表达式中使用的(自 C++20 起),该对象的动态类型为 constexpr-unknown
  • 对于这样的引用,它不是可用常量表达式(自 C++20 起),该引用被视为绑定到未指定类型的被引用类型的对象,该对象的生命周期以及所有子对象的生命周期都包含整个常量求值,并且其动态类型为 constexpr-unknown。

[编辑] 整型常量表达式

整型常量表达式 是指一个整型或无作用域枚举类型的表达式,它被隐式转换为纯右值 (prvalue),且转换后的表达式是一个核心常量表达式。

如果在一个期望整型常量表达式出现的地方使用了一个类类型的表达式,该表达式会 语境隐式转换 为整型或无作用域枚举类型。

[编辑] 转换后的常量表达式

类型 T转换后的常量表达式 是指一个 隐式转换 为类型 T 的表达式,其中转换后的表达式是一个常量表达式,且隐式转换序列仅包含:

(自 C++17 起)

并且如果发生任何 引用绑定,则它只能是 直接绑定

以下语境需要转换后的常量表达式:

(自 C++14 起)
(自 C++26 起)

类型为 bool 的语境转换后的常量表达式 是指一个 语境转换bool 类型的表达式,其中转换后的表达式是一个常量表达式,且转换序列仅包含上述转换。

以下语境需要类型为 bool 的语境转换后的常量表达式:

(C++23 前)
(自 C++17 起)
(C++23 前)
(自 C++20 起)


组成实体

对象 obj组成值定义如下:

  • 如果 obj 具有标量类型,则组成值是 obj 的值。
  • 否则,组成值是 obj 的任何直接 子对象(非 联合体 的非活动成员)的组成值。

对象 obj组成引用包括以下引用:

  • obj 的任何具有引用类型的直接成员
  • obj 的任何直接子对象(非联合体的非活动成员)的组成引用

变量 var组成值组成引用定义如下:

  • 如果 var 声明了一个对象,则组成值和引用是该对象的组成值和引用。
  • 如果 var 声明了一个引用,则组成引用是该引用。

对于变量 var 的任何组成引用 ref,如果 ref 绑定到一个临时对象或其子对象,且该临时对象的生命周期被延长至 ref 的生命周期,则该临时对象的组成值和引用也是 var 的组成值和引用,递归地定义。

constexpr 可表示的实体

具有静态存储期的对象在程序的任何点都是 constexpr 可引用的

具有自动存储期的对象 obj 从点 Pconstexpr 可引用的,如果包含变量 var 的最小作用域和包含 P 的最小作用域是同一个函数参数作用域(该作用域不与 requires 表达式 的参数列表关联),其中 var 是对应于 obj 的完整对象的变量,或者生命周期被 延长obj 的变量。

对象或引用 x 在点 Pconstexpr 可表示的,如果满足以下所有条件:

  • 对于 x 的每个指向对象 obj 的组成值,objP 是 constexpr 可引用的。
  • 对于 x 的每个指向对象 obj 之后的组成值,objP 是 constexpr 可引用的。
  • 对于 x 的每个引用对象 obj 的组成引用,objP 是 constexpr 可引用的。
(自 C++26 起)

常量初始化的实体

变量或临时对象 obj常量初始化 的,如果满足以下所有条件:

  • 它要么有一个初始化器,要么其类型是 const 默认可构造的
  • 其初始化的 完整表达式 在需要常量表达式的语境中是一个常量表达式,但如果 obj 是一个对象,则该完整表达式也可以为 obj 及其子对象调用 constexpr 构造函数,即使这些对象是非字面量类类型。
(直到 C++26)

变量 var常量可初始化 的,如果满足以下所有条件:

  • 其初始化的 完整表达式 在需要常量表达式的语境中是一个常量表达式,其中所有 contract 断言 都使用 “忽略” 求值语义。
  • var 的初始化声明之后立即,由 var 声明的对象或引用是 constexpr 可表示的。
  • 如果由 var 声明的对象或引用 x 具有静态或线程存储期,则 x 在最近的点是 constexpr 可表示的,该点的直接作用域是命名空间作用域,并且该作用域位于 var 的初始化声明之后。

一个常量可初始化的变量是常量初始化的,如果它要么有一个初始化器,要么其类型是 const 默认可构造的

(自 C++26 起)

可在常量表达式中使用

一个变量是 潜在常量,如果它是 constexpr 变量,或者它具有引用类型或非易失性 const 限定的整型或枚举类型。

一个常量初始化的潜在常量变量 var 在点 P可在常量表达式中使用 的,如果 var 的初始化声明 DP 可达,并且满足以下任一条件:

  • var 是一个 constexpr 变量。
  • var 没有被初始化为 翻译单元本地 值。
  • PD 在同一个翻译单元中。

对象或引用在点 P可在常量表达式中使用 的,如果它是以下实体之一:

  • P 点可在常量表达式中使用的变量
  • 非易失性 const 限定字面量类型的临时对象,其生命周期被延长至在 P 点可在常量表达式中使用的变量的生命周期
  • 模板形参对象
  • 字符串字面量对象
  • 上述任何对象的非可变子对象
  • 上述任何对象的引用成员
(直到 C++26)

对象或引用在点 P潜在地可在常量表达式中使用 的,如果它是以下实体之一:

  • P 点可在常量表达式中使用的变量
  • 非易失性 const 限定字面量类型的临时对象,其生命周期被延长至在 P 点可在常量表达式中使用的变量的生命周期
  • 模板形参对象
  • 字符串字面量对象
  • 上述任何对象的非可变子对象
  • 上述任何对象的引用成员

对象或引用在点 P可在常量表达式中使用 的,如果它是在 P 点潜在地可在常量表达式中使用的对象或引用,并且在 P 点是 constexpr 可表示的。

(自 C++26 起)

显式常量求值的表达式

以下表达式(包括到目标类型的转换)是 显式常量求值 的:

一个求值是否发生在显式常量求值语境中,可以通过 std::is_constant_evaluatedif consteval(C++23 起) 来检测。

(自 C++20 起)

[编辑] 常量求值所需的函数和变量

以下表达式或转换是 潜在常量求值 的:

一个函数是 常量求值所需的,如果它是一个 constexpr 函数,并且被一个潜在常量求值的表达式 命名

一个变量是 常量求值所需的,如果它要么是一个 constexpr 变量,要么是具有非易失性 const 限定的整型类型或引用类型,并且表示它的 标识符表达式 是潜在常量求值的。

如果一个函数 或变量(C++14 起) 是常量求值所需的,则会触发默认函数的定义和 函数模板 特化或 变量模板 特化(C++14 起)(C++14 起) 的实例化。

[编辑] 常量子表达式

常量子表达式 是指一个表达式,其作为表达式 e子表达式 进行求值不会阻止 e 成为 核心常量表达式,其中 e 不是以下任何表达式:

(自 C++20 起)

[编辑] 注释

特性测试宏 标准 特性
__cpp_constexpr_in_decltype 201711L (C++20)
(DR11)
当常量求值需要时生成函数和变量定义
__cpp_constexpr_dynamic_alloc 201907L (C++20) constexpr 函数中动态存储期的操作
__cpp_constexpr 202306L (C++26) void* 的 constexpr 转换:迈向 constexpr 类型擦除
202406L (C++26) constexpr placement new 和 new[]
__cpp_constexpr_exceptions 202411L (C++26) constexpr 异常

[编辑] 示例

[编辑] 缺陷报告

以下行为变更的缺陷报告被追溯应用于之前发布的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确行为
CWG 94 C++98 算术常量表达式不能
包含变量和静态数据成员
它们可以
CWG 366 C++98 涉及字符串字面量的表达式
可能是整型常量表达式
它们不是
CWG 457 C++98 涉及 volatile 变量的表达式
可能是整型常量表达式
它们不是
CWG 1293 C++11 字符串字面量是否
可在常量表达式中使用尚不明确
它们是可用的
CWG 1311 C++11 volatile glvalue 可以在常量表达式中使用 禁止
CWG 1312 C++11 reinterpret_cast 在常量表达式中是被禁止的,
但是与 void* 之间的转换可能达到相同的效果
禁止从类型 cv void* 转换
为对象指针类型
到对象指针类型
CWG 1313 C++11 允许未定义行为;
所有指针减法都被禁止
禁止未定义行为;相同数组的
指针减法是可以的
CWG 1405 C++11 对于可在常量表达式中使用的对象,
其可变子对象也是可用的
它们是不可用的
CWG 1454 C++11 不允许通过 constexpr
函数经由引用传递常量
允许
CWG 1455 C++11 转换后的常量表达式只能是纯右值 可以是左值
CWG 1456 C++11 地址常量表达式不能
指定数组末尾之后一个地址
允许
CWG 1535 C++11 typeid 表达式的操作数是
多态类类型,即使不涉及运行时检查,也不是核心常量表达式
表达式,即使不涉及运行时检查,也不是核心常量表达式
操作数约束
仅限于多态类类型的
多态类类型的 glvalue
CWG 1581 C++11 常量求值所需的函数
不需要被定义或实例化
需要
CWG 1613 C++11 核心常量表达式可以求值任何
lambda 表达式内部的 ODR 使用的引用
某些引用可能
不能被求值
CWG 1694 C++11 将临时对象的值绑定到静态存储
期引用是一个常量表达式
它不是一个
常量表达式
CWG 1872 C++11 核心常量表达式可以调用 constexpr 函数模板
不满足 constexpr 函数要求的实例化
此类实例化
不能被调用
CWG 1952 C++11 标准库未定义行为
需要被诊断
是否被诊断
尚不明确
CWG 2022 C++98 常量表达式的确定可能
取决于是否执行了复制省略
假设总是执行复制省略
假设总是执行复制省略
CWG 2126 C++11 const 限定字面量类型的常量初始化且生命周期延长的临时对象在常量表达式中不可用
const 限定字面量类型的常量初始化且生命周期延长的临时对象在常量表达式中不可用
可用
CWG 2129 C++11 整数字面量不是常量表达式 它们是
CWG 2167 C++11 局部于求值的非成员引用
使得求值变为非 constexpr
允许非成员
允许非成员引用
CWG 2278 C++98 CWG issue 2022 的解决方案不可实现 假设总是执行复制省略
永不执行
CWG 2299 C++14 <cstdarg> 中的宏是否
可以在常量求值中使用尚不明确
va_arg 被禁止,
va_start 未指定
CWG 2400 C++11 在常量表达式中不可用的对象上调用 constexpr 虚函数,且该对象的生命周期在包含调用的表达式之外开始,这可能是一个常量表达式
在常量表达式中不可用的对象上调用 constexpr 虚函数,且该对象的生命周期在包含调用的表达式之外开始,这可能是一个常量表达式
表达式之外开始,这可能是一个常量表达式
它不是一个
常量表达式
CWG 2490 C++20 (伪)析构函数调用缺乏
常量求值中的限制
添加了限制
CWG 2552 C++23 当求值核心常量表达式时,控制
流不能穿过非块变量的声明
它可以
CWG 2558 C++11 不确定值可能是常量表达式 不是常量表达式
CWG 2647 C++20 volatile 限定类型的变量可能是潜在常量 它们不是
CWG 2763 C++11 [[noreturn]] 的违反不需要
在常量求值期间被检测到
需要
CWG 2851 C++11 转换后的常量表达式
不允许浮点转换
允许非窄化
允许非窄化浮点转换
CWG 2907 C++11 核心常量表达式不能应用
左值到右值转换到 std::nullptr_t glvalue
可以应用此类
转换
CWG 2909 C++20 没有初始化器的变量只有在其
默认初始化导致执行某些初始化的情况下才能被常量初始化
默认初始化导致执行某些初始化的情况下才能被常量初始化
只有在其类型是
只有在其类型是
const 默认可初始化的时才能被常量初始化
CWG 2924 C++11
C++23
违反 [[noreturn]] (C++11) 或
违反 [[noreturn]] (C++11) 或
[[assume]] (C++23) 约束的表达式是否是核心常量表达式尚不明确
它是
它是实现定义的
P2280R4 C++11 求值包含标识符表达式
*this 的表达式,且该表达式引用生命周期
在此求值之外开始的对象或引用,则不是常量表达式
它可能是一个
常量表达式

[编辑] 参见

constexpr 说明符(C++11) 指定变量或函数的值可以在编译时计算[编辑]
(C++11)(C++17 中已弃用)(C++20 中已移除)
检查类型是否为字面量类型
(类模板) [编辑]
C 文档 中关于 常量表达式 的内容