1

このコードを検討してください:

#include <iostream>
#include <array>

template <typename Type>
struct Constant
{
    constexpr Constant(const Type source) : _data({{source}}) {;}
    constexpr Constant(const std::array<Type, 1> source) : _data(source) {;}
    constexpr Constant<Type> operator()() const {return _data;}
    constexpr operator Type() const {return _data[0];}
    const std::array<Type, 1> _data;
    static constexpr Constant<Type> pi = 3.1415926535897932384626433832795028841971693993751058209749445L;
};

int main(int argc, char* argv[])
{
    std::cout<<Constant<double>::pi()<<std::endl;
    return 0;
}

g++4.7.3and (これは(フランス語で申し訳ありません)g++4.8.0への未定義の参照です) でコンパイラ エラーが発生します。pi

/tmp/cctdvPfq.o: dans la fonction « main »:
main.cpp:(.text.startup+0xd): référence indéfinie vers « Constant<double>::pi »
collect2: erreur: ld a retourné 1 code d'état d'exécution

g++4.7.3私のシステムは新規インストール (とを初めて使用g++4.8.0) であるため、システム構成によるものなのか、コンパイラによるものなのかわかりません。コンパイラからのものである場合、どこに問題がありますか?

編集:なぜこれが機能しているのですか? (配列なしバージョン)

#include <iostream>
#include <array>

template <typename Type>
struct Constant
{
    constexpr Constant(const Type source) : _data(source) {;}
    constexpr Constant<Type> operator()() const {return _data;}
    constexpr operator Type() const {return _data;}
    const Type _data;
    static constexpr Constant<Type> pi = 3.1415926535897932384626433832795028841971693993751058209749445L;
};

int main(int argc, char* argv[])
{
    std::cout<<Constant<double>::pi()<<std::endl;
    return 0;
}
4

1 に答える 1

6

プログラムでODR 使用さpiれないように、呼び出し演算子 on の呼び出しを避けることができ、コンパイラはインライン化できる値と同じように扱うことができるため、そのデータ メンバーの定義は必要ありません。pistatic

std::cout << Constant<double>::pi << std::endl;
//                             ^^

または、 の呼び出し演算子を呼び出し続け、名前空間スコープで静的データ メンバーの定義piを提供し、元のコードで asの呼び出し演算子を使用することもできます。Constant<double>

template <typename Type>
struct Constant
{
    // ...
    static constexpr Constant<Type> pi = /* ... */;
};

template<typename Type>
constexpr Constant<Type> Constant<Type>::pi;

C++11 標準のパラグラフ 9.4.2/3 によると:

不揮発性const静的データ メンバーが整数型または列挙型の場合、クラス定義でのその宣言は、代入式であるすべての初期化子句が 定数式であるブレースまたはイコール初期化子を指定できます (5.19)。 . リテラル型の静的データ メンバーは、指定子を使用してクラス定義で宣言できます。その場合、その宣言は、割り当て式 であるすべての初期化子節が定数式であるブレースまたは等号初期化子を指定するものとします。[ 注: どちらの場合も、メンバーは定数式に現れる場合があります。—終わりのメモ]constexprメンバーは、プログラムで ODR 使用 (3.2) され、名前空間スコープ定義に初期化子が含まれていない場合でも、名前空間スコープで定義されます

于 2013-05-09T17:43:31.420 に答える