最初の例でdは、は定数式によって初期化されてS::cいません。
定数式で初期化された、先行初期化を伴う不揮発性constオブジェクト
(C ++ 11 [expr.const] p2、左辺値から右辺値への変換に関する箇条書きを参照)。これは、の初期化がS::cの初期化に先行しないためですd。したがって、静的初期化はS::c(定数式によって初期化されるため)に使用されますが、動的初期化はに使用できますd。
静的初期化は動的初期化に先行するため、動的初期化子によってd初期化さ50れます。コンパイラーは、の動的初期化を静的初期化に変換することを許可されていますが、変換する場合、動的初期化を使用できるすべての変数が実際に動的初期化を使用した場合dの値を生成する必要があります。dこの場合、dはいずれかの方法で初期化され50ます。詳細については、C ++ 11[basic.start.init]p2を参照してください。
最初の例に追加して、静的初期化が;constexprに使用されることを保証する方法はありません。dこれを行うには、初期化を並べ替える必要があります。ただし、追加constexprすると最初の例の診断が生成され、少なくとも動的初期化が使用されていないことを確認できます(静的初期化またはコンパイルエラーが発生します)。
2番目のケースを更新して、静的初期化が次のように使用されるようにすることができます。
struct S {
static const int c; // do not use constexpr here
};
constexpr int S::c = 5;
constexpr int d = 10 * S::c;
constexpr定義ではない変数宣言で使用すること、または初期化子を含まない変数宣言で使用することは不正な形式であるため、constのconstexpr定義内で使用する必要はありませんstruct S。この規則には1つの例外があります。これはstatic constexpr、クラス内で指定された初期化子を使用して、リテラルの非整数型のデータメンバーを定義する場合です。
struct T { int n; };
struct U {
static constexpr T t = { 4 };
};
constexpr T U::t;
この場合、constexprは、初期化子を提供できるようにするためにクラスの定義で使用するconstexpr必要があり、定数式内で使用できるようにするために静的データメンバーの定義で使用する必要があります。