興味深いことに、Blob::a
代わりに使用すると、clang
文句はありません。
auto c = Blob::a;
これは、それが臭気を帯びているかどうかを判断する上で重要ではありません。したがって、これは最適化を行わずにclang 3.7clang
で再現できるバグのようです。クラス外の定義を追加すると問題が修正されるため、これはodrの問題であることがわかります(ライブで参照してください)。
constexpr float Blob::a ;
では、静的な constexpr クラス メンバーを定義する必要があるのはいつでしょうか? これは、セクション9.4.2
[class.static.data]で説明されています (私のものは今後も強調されます)。
リテラル型の静的データ メンバーは、constexpr 指定子を使用してクラス定義で宣言できます。その場合、その宣言は、割り当て式であるすべての初期化子節が定数式であるブレースまたは等号初期化子を指定するものとします。[ 注: どちらの場合も、メンバーは定数式に現れる場合があります。--end note ]メンバーがプログラムで ODR 使用 (3.2)され、名前空間スコープ定義に初期化子が含まれていない場合、メンバーは名前空間スコープで定義されます。
ODR 使用の場合は定義が必要です。臭気使用ですか?いいえそうではありません。3.2
セクション[basic.def.odr]の元の C++11 の文言には、次のように書かれています。
式は、未評価のオペランド (第 5 節) またはその部分式でない限り、評価される可能性があります。名前が潜在的に評価される式として表示される変数は、それが定数式(5.19)に表示されるための要件を満たし、左辺値から右辺値への変換 (4.1) がすぐに適用されるオブジェクトでない限り、odr-usedです。
a
両方の条件を満たす場合、これは定数式であり、左辺値から右辺値への変換がすぐに適用されます。欠陥レポート 712は、欠陥レポートであるため、C++11 に適用される文言を変更し、3.2
現在は次のように述べています。
名前が潜在的に評価される式 ex として表示される変数 xは、左辺値から右辺値への変換 (4.1) を x に適用して、重要な関数を呼び出さない定数式 (5.19) を生成しない限り、odr で使用されます。 x はオブジェクト、ex は式 e の潜在的な結果のセットの要素です。ここで、左辺値から右辺値への変換 (4.1) が e に適用されるか、e は破棄値式です。
一致する潜在的な結果は次のようになります。
e が id-expression (5.1.1) の場合、セットには e のみが含まれます。
これは定数式であり、左辺値から右辺値への変換が適用されるため、odr は使用されません。