web-dev-qa-db-ja.com

静的constexprメンバー変数について

C++ 11のstatic constexprメンバー変数に関していくつか混乱があります。

First.hpp

template<typename T>
struct cond_I
{ static constexpr T value = 0; }; 


// specialization 
template<typename T>
struct cond_I< std::complex<T> >
{ static constexpr std::complex<T> value = {0,1}; }; 

Main()関数内

cout << cond_I<double>::value << endl;            // this works fine
cout << cond_I< complex<double> >::value << endl; // linker error

ただし、次の行をfirst.hppに追加すると、すべて正常に動作します。

template<typename T1> 
constexpr std::complex<T1> cond_I< std::complex<T1> >::value;

私が理解していること(私は間違っている可能性があります)は、cond_I< std::complex<double> >::valueには定義が必要ですが、前のケースでは宣言しかないということです。しかし、cond_I<double>::valueはどうですか?なぜそれは定義を必要としないのですか?

もう一度、別のヘッダーファイルsecond.hppには、

Second.hpp

// empty struct
template<typename T>
struct eps
{ };


// special cases
template<>
struct eps<double>
{
  static constexpr double value = 1.0e-12;
};

template<>
struct eps<float>
{
  static constexpr float value = 1.0e-6;
};

この場合、以下のコードはeps<>::valueの定義がなくても完全に機能します。

Main()関数内

cout << eps<double>::value << endl;    //  works fine
cout << eps<float>::value << endl;     //  works fine

これらのシナリオでのstatic constexprメンバー変数のさまざまな動作を誰かに説明してもらえますか?

これらの動作は、gcc-5.2およびclang-3.6でも同じです。

19
Titas Chanda

標準に従って9.4.2/p3静的データメンバー[class.static.data]Emphasis Mine):

不揮発性のconst静的データメンバーが整数型または列挙型である場合、クラス定義での宣言は、割り当て式であるすべての初期化子句が定数式であるブレースまたはイコール初期化子を指定できます(5.20 )。 リテラル型の静的データメンバーは、constexpr指定子を使用してクラス定義で宣言できます。宣言されている場合、その宣言は、すべての初期化子節がは代入式です。定数式です。[注:メンバーは定数式で表示される可能性があります。—終了注記]メンバーが名前空間スコープで定義されている場合、メンバーがodrで使用されている場合(3.2)プログラムと名前空間スコープの定義には初期化子を含めないでください。

M.Mが前にコメントで説明したように、ostream::operator<<(ostream&, const complex<T>&)は参照渡しなので、値はプログラムでodrで使用されていると見なされます。したがって、上記の表現が示すように、定義を提供する必要があります。

基本的な型が値によって渡されることがすでにわかっているので、そのため、定義は必要ありません。

13
101010