名稱空間
變體
操作

常量表達式

來自 cppreference.com
< 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 文件中有關常量表達式的內容