命名空间
变体
操作

常量表达式

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
跳转语句
函数
函数声明
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++ 要求表达式能求值为整数或枚举常量

满足所有下列条件的表达式是整型常量表达式 (integral constant-expression) 

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

其他常量表达式类别

其他表达式仅为了常量初始化的目的而被认为是常量表达式。这样的常量表达式必须是下列表达式之一

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

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

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

地址常量表达式 (address constant expression) 是满足所有下列条件的指针类型表达式

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

引用常量表达式 (reference constant expression) 是满足所有下列条件的引用类型表达式

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

成员指针常量表达式 (pointer-to-member constant expression) 是一个成员指针类型的表达式,其中该指针是通过对限定标识符应用取地址运算符创建的,其前可有显式成员指针转换。

(C++11 前)

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

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

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

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

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

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

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

(C++26 起)

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

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

[编辑] 字面类型

下列类型统称为字面类型 (literal types) 

(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 的非分配形式,且布局实参满足所有下列条件
    • 它指向
    • 如果 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-使用
    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-未知的
  • 对于这样一个不可在常量表达式中使用的(C++20 起)引用,该引用被视为绑定到一个未指定的被引用类型的对象,该对象的生存期及其所有子对象的生存期包含整个常量求值过程,并且其动态类型是 constexpr-未知的。

[编辑] 整型常量表达式

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

如果一个类类型的表达式被用在需要整型常量表达式的地方,该表达式将被按语境隐式转换为整型或无作用域枚举类型。

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

类型为 T经转换的常量表达式 (converted constant expression) 是一个隐式转换为类型 T 的表达式,其中转换后的表达式是常量表达式,并且隐式转换序列只包含

(C++17 起)

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

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

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

类型为 bool 的语境转换的常量表达式(contextually converted constant expression of type bool)是一个表达式,它语境转换为 bool,其中被转换的表达式是一个常量表达式,且转换序列只包含上述转换。

下列语境要求一个类型为 bool 的语境转换的常量表达式

(直至 C++23)
(C++17 起)
(直至 C++23)
(C++20 起)


构成实体

一个对象 obj构成值(constituent values)定义如下

  • 如果 obj 具有标量类型,其构成值就是 obj 的值。
  • 否则,其构成值是 obj 的除非活跃联合体成员外的任何直接子对象的构成值。

一个对象 obj构成引用(constituent references)包括以下引用

  • obj 的任何具有引用类型的直接成员
  • obj 的除非活跃联合体成员外的任何直接子对象的构成引用

一个变量 var构成值构成引用定义如下

  • 如果 var 声明了一个对象,其构成值和引用就是该对象的构成值和引用。
  • 如果 var 声明了一个引用,其构成引用就是该引用本身。

对于变量 var 的任何构成引用 ref,如果 ref 绑定到一个临时对象或其子对象,且该临时对象的生存期被延长至 ref 的生存期,那么该临时对象的构成值和引用也递归地成为 var 的构成值和引用。

可用 constexpr 表示的实体

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

具有自动存储期的对象 obj 从点 P 开始是可用 constexpr 引用的,如果包围变量 var 的最小作用域和包围 P 的最小作用域是同一个函数形参作用域,且该作用域不与 requires 表达式的形参列表相关联。其中 var 是对应于 obj 的完整对象或 obj 的生存期所延长到的变量。

一个对象或引用 x 在点 P可用 constexpr 表示(constexpr-representable)的,如果满足以下所有条件

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

常量初始化的实体

一个变量或临时对象 obj常量初始化(constant-initialized)的,如果满足以下所有条件

  • 它要么有初始值设定项,要么其类型是可 const 默认构造的。
  • 其初始化的全表达式在要求常量表达式的语境中是常量表达式,但有一个例外:如果 obj 是一个对象,该全表达式也可以为 obj 及其子对象调用 constexpr 构造函数,即使这些对象属于非字面类类型。
(直到 C++26)

一个变量 var可常量初始化(constant-initializable)的,如果满足以下所有条件

  • 其初始化的全表达式在要求常量表达式的语境中是常量表达式,其中所有契约断言都使用“忽略”求值语义。
  • 紧随 var 的初始化声明之后,由 var 声明的对象或引用是可用 constexpr 表示的。
  • 如果由 var 声明的对象或引用 x 具有静态或线程存储期,则 x 在紧邻作用域为命名空间作用域且位于 var 的初始化声明之后最近的点是可用 constexpr 表示的。

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

(C++26 起)

可用于常量表达式

一个变量是潜在常量(potentially-constant)的,如果它是一个 constexpr 变量,或者它具有引用类型或非 volatile 的 const 限定的整型或枚举类型。

一个经过常量初始化的潜在常量变量 var 在点 P可用于常量表达式(usable in constant expressions)的,如果 var 的初始化声明 DP 可达,并且满足以下任一条件

  • var 是一个 constexpr 变量。
  • var 未被初始化为翻译单元局部(TU-local)值。
  • PD 在同一个翻译单元中。

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

  • 一个在 P 点可用于常量表达式的变量
  • 一个非 volatile 的 const 限定字面类型的临时对象,其生存期被延长至一个在 P 点可用于常量表达式的变量的生存期
  • 一个模板形参对象
  • 一个字符串字面量对象
  • 以上任一者的非可变子对象
  • 以上任一者的引用成员
(直到 C++26)

一个对象或引用在点 P潜在地可用于常量表达式(potentially usable in constant expressions)的,如果它是以下实体之一

  • 一个在 P 点可用于常量表达式的变量
  • 一个非 volatile 的 const 限定字面类型的临时对象,其生存期被延长至一个在 P 点可用于常量表达式的变量的生存期
  • 一个模板形参对象
  • 一个字符串字面量对象
  • 以上任一者的非可变子对象
  • 以上任一者的引用成员

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

(C++26 起)

明显常量求值的表达式

下列表达式(包括到目标类型的转换)是明显常量求值(manifestly constant-evaluated)的

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

(C++20 起)

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

下列表达式或转换是潜在常量求值(potentially constant evaluated)的

一个函数是常量求值所需(needed for constant evaluation)的,如果它是一个 constexpr 函数且被一个潜在常量求值的表达式指名

一个变量是常量求值所需的,如果它是一个 constexpr 变量,或者具有非 volatile 的 const 限定整型类型或引用类型,并且指代它的标识符表达式是潜在常量求值的。

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

[编辑] 常量子表达式

常量子表达式(constant subexpression)是这样一个表达式,其作为表达式 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 就地 newnew[]
__cpp_constexpr_exceptions 202411L (C++26) constexpr 异常

[编辑] 示例

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 发布时的行为 正确的行为
CWG 94 C++98 算术常量表达式不能
涉及变量和静态数据成员
推导指引可以有尾随的requires子句
CWG 366 C++98 涉及字符串字面量的表达式
可以是整型常量表达式
它们没有
CWG 457 C++98 涉及 volatile 变量的表达式
可以是整型常量表达式
它们没有
CWG 1293 C++11 不清楚字符串字面量是否
可用于常量表达式
它们是可用的
CWG 1311 C++11 volatile 左值可用于常量表达式 已禁止
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 表达式,其操作数是
多态类类型,不是核心常量
表达式,即使不涉及运行时检查
操作数的约束
被限制为
多态类类型的左值
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
限定字面类型的临时对象不可用于常量表达式
可用
CWG 2129 C++11 整数字面量不是常量表达式 它们是
CWG 2167 C++11 求值局部的非成员引用
使得该求值非 constexpr
非成员
引用是允许的
CWG 2278 C++98 CWG 问题 2022 的解决方案不可实现 假定复制消除
从不执行
CWG 2299 C++14 不清楚 <cstdarg> 中的宏是否
可以在常量求值中使用
va_arg 被禁止,
va_start 未指明
CWG 2400 C++11 在一个不可用于常量表达式且其生存期始于
包含该调用的表达式之外的对象上调用一个 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 左值
可以应用此类转换
转换
CWG 2909 C++20 一个没有初始值设定项的变量只能在
其默认初始化导致
执行了某些初始化时才能被常量初始化
仅当其类型是
可 const 默认
初始化时才能被常量初始化
CWG 2924 C++11
C++23
未指明一个违反 [[noreturn]] (C++11) 或
[[assume]] (C++23) 约束的表达式
是否是核心常量表达式
它是
实现定义
P2280R4 C++11 求值一个包含标识符表达式
*this 的表达式,该表达式引用一个生存期
始于此求值之外的对象或引用,不是一个常量表达式
它可以是
常量表达式

[编辑] 参阅

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