N3337 5.19 Constant expressions
N3337 5.19 Constant expressionsを稚拙な英語力ながら翻訳したので掲載しておきます。
誤訳等があれば、指摘お願いします。
特定の場合では、この項で詳しく述べるような追加要求を満たすような式が必要になるし、そうでない場合でも式がこれらの要求を満たしているかどうかで意味が異なってくる
次の条件を満たすような式はconstant expressionsと呼ばれる。(Constant expressionはコンパイル時に評価され得る)
constant-expression:
conditional-expression
conditional-expressionは、潜在的に評価された次に列挙するようなsubexpressionを含んでいなければcore constant expressionである。ただし、評価されない論理積・論理和・条件式、のsubexpressionは考慮されない。(オーバーロードされた演算子は関数を呼び出す)
・this (非静的メンバ関数の本体に暗黙の変換の結果を含む、クラスメンバアクセス式の後置式、として表れていない場合)
・リテラルクラスのconstexprコンストラクタとconstexpr関数以外の関数呼び出し(オーバーロードの解決は普段通り適用される)
・constexpr関数やconstexprコンストラクタの定義の外での未定義動作のconstexpr関数や、未定義動作のconstexprコンストラクタの呼び出し
・constant expressionを生成しないような引数を用いてのconstexpr関数の呼び出し
例
constexpr const int* addr(const int& ir) { return &ir; } // OK static const int x = 5; constexpr const int* xp = addr(x); // OK constant expressionなアドレス constexpr const int* tp = addr(5); // エラー 一時アドレスの取得はconstant expressionではない
・constant expressionを生成しないような引数による、初期化リストのみからなるconstexprコンストラクタの呼び出し
int x; // not constant struct A { constexpr A(bool b) : m(b?42:x) { } int m; }; constexpr int v = A(true).m; // OK constexpr int w = A(false).m; // エラー mの初期化に用いられるxが定数でない
・constexpr関数又はconstexprコンストラクタの再帰呼び出しが処理系の定義する制限を超える場合(Annex Bを参照)
Annex BにおいてRecursive constexpr function invocations [512].と定義されている
・数学上定義されないような値、又は特定の型で扱える範囲外のその型の値。
・ラムダ式
・次の場合を除く左辺値から右辺値への変換
・constant expressionで事前に初期化された非volatileなconstオブジェクトを参照する整数型のglvalue又はenum
・constexpr修飾で定義された、非volatileのオブジェクトかそのようなサブオブジェクトを参照するリテラル型のglvalue
・constant expressionで初期化された寿命の尽きていない一時オブジェクトを参照するリテラル型のglvalue
・非activeなunionのメンバやサブオブジェクトを参照するglvalueに適用される左辺値から右辺値への変換
・constant expressionによって初期化されていない状態の値やデータメンバ参照を参照するid-expression
・dynamic cast
・reinterpret_cast
・擬似destructorの呼び出し
・インクリメント及びデクリメント操作
・多態クラス型に対するtypeid式
・new式
・delete式
・ポインタ同士の減算
・結果が不特定な場所での比較に関連するような演算子(rational or equality operator)
・代入及び複合代入
・throw式
literal constant expressionはリテラル型のprvalue core constant expressionであり、ポインタ型ではない
integral constant expressionは整数型もしくはunscopedな列挙型のliteral constant expressionである(そのような式は配列の大きさやbit-fieldの長さ、基礎となる型の固定されていない列挙子の初期化、nullポインタ定数、及びアラインメントに用いられる)
literal constant expression及び暗黙の型変換がユーザ定義変換、左辺値から右辺値への変換、整数拡張、整数変換、その他の狭義の変換のみを含む場合には、暗黙の型変換が許され、変換されたT型のconstant expressionは、literal constant expressionである(そのような式はcase式や、基礎となる型の固定された列挙型の初期化子、整数又は列挙型の非型テンプレート引数に用いられる)
reference constant expressionは、static要素、又は関数を指し示すlvalue core constant expressionである
address constant expressionは、staticオブジェクトのアドレス、関数のアドレスへのアドレス、null pointerの値へのアドレス、又はstd::nullprt_t型のprvalue core constant expressionのアドレス、を評価するポインタ型のprvalue core constant expressionである
まとめて、literal constant expression、reference constant expression、address constant expressionのことをconstant expressionと呼ぶ。
いくつかの場面では、constant expressionは必ずコンパイル時に評価されなければならないが、それ以外は実行時に評価されるかもしれない。 規格では浮動小数点の演算精度に関して制限を課さないので、コンパイル時と実行時における同じ式の浮動小数点演算の結果が同じである保証は無い。
bool f() { char array[1 + int(1 + 0.2 - 0.1 - 0.1)]; // 必ずコンパイル時に計算される int size = 1 + int(1 + 0.2 - 0.1 - 0.1); // 実行時に計算されるかもしれない return sizeof(array) == size; }
f()の結果がtrueであるかfalseであるかは未定義である。
整数型のconstant expressionが要求される場所において、リテラル型の式を用いる場合には、そのクラスは1つの非明示的な整数型又はunscopedな列挙型への変換関数を持つものとし、その変換関数はconstexprであるものとする。
struct A { constexpr A(int i) : val(i) { } constexpr operator int() { return val; } constexpr operator long() { return 43; private: int val; }; template<int> struct X { }; constexpr A a = 42; X<a> x; // OK 一意なintへの変換 int ary[a]; // エラー 曖昧な変換(intとlongの2つの候補が存在)