2017-07-10 4 views
14

次はC++ 14でgccと打ち鳴らすの両方でコンパイルに失敗しますが、C++ 1Zに成功:constexpr静的データメンバーの再定義は今では許可されていますか? (インラインconstではなく)?

struct Cls { 
    static constexpr int N = 0; 
}; 
constexpr int Cls::N; 
constexpr int Cls::N; 

C++ 14のエラーが予測可能である:redefinition of ‘constexpr const int Cls::N’

に何が変わりましたこれを法的にする?私が見つかりました:

n4659 10.1.5 [dcl.constexpr]

関数または静的データメンバは、constexprので宣言 指定子は暗黙インライン関数または変数

ある

だから私はそれがインライン変数と関係があるかもしれないと思ったが、両方のコンパイラの下で、次のことはC++ 1zで失敗する

struct Cls { 
    static inline const int N = 0; 
}; 
inline const int Cls::N; // note, only one definition here 

答えて

12

C++ 17には、事前に(通常、各翻訳単位は.cppファイルおよびその逆ですが、これは必須ではない)、正確に1個の翻訳単位でクラス外のすべてのstatic変数を再宣言する必要がありました。あなたが指摘したように、C++ 17では、クラスメンバー変数inlineが導入され、static constexpr変数が自動的に修飾されます。あなたは、あなたの第二の例で見たように、クラスの外inline変数を再宣言することができないですが、以前にあなたが許可された(そして必要な実際には)そうすることが、構文は推奨されませんので、例外がconstexprのために作られました。

[class.static.data] p2では、非インラインメンバーの構文が許可されています(「クラス定義内の非インライン静的データメンバーの宣言は定義ではなく、 不完全クラス定義内のインライン で定義されていない静的データメンバの定義は、メンバのクラス定義を囲む名前空間スコープ内に現れなければならない "外のクラス宣言および非constexprデータ(強調付加)のためにそれらを必要とする:

クラス定義の宣言 が毎 イニシャライザ節 にブレース-OR-等しい初期を指定することができ

非揮発性非インラインconst静的データメンバは、一体または列挙型である場合、 代入式は、 定数式(8.20)です。 ODR利用(6.2)プログラムであり、 名前空間スコープ定義がイニシャライザを含んではならない場合メンバーは依然として 名前空間の範囲に定義されなければなりません。インライン 静的データメンバーはクラス定義 で定義され、ブレースまたは同等の初期化子を指定することができます。 のメンバーがconstexpr指定子で宣言されている場合、 の名前空間のスコープには、の初期設定なしで再宣言される可能性があります(この使用は推奨されていません; D.1を参照)。他の静的データメンバーの宣言は、 ブレースまたは同等の初期化子を指定してはならない。

そしてここでは、非推奨のノート、静的constexprのデータメンバーのD.1再宣言は、[depr.static_constexpr]です:前にC++の国際規格、constexprの静的データメンバとの互換性のため

は重複再宣言することができます初期化子を持たない クラスの外にあります。この使用法は推奨されていません。 [例:

struct A { 
    static constexpr int n = 5; // definition (declaration in C++ 2014) 
}; 
constexpr int A::n; // redundant declaration (definition in C++ 2014) 

- 端例]

関連する問題