2

次のコードは、Def::DEFAULT; への未定義の参照でコンパイルに失敗するという、私が遭遇した問題を示しています。

ただし、メインの 2 行目をコメント アウトすると、コンパイルして正常に実行されます。int にキャストするか、Val クラスの int データ メンバーに直接割り当てることで、DEFAULT に割り当てられた値を「見る」ことができます。

template <typename T, T def>
class Def {
 public:
    static const T DEFAULT = def;
    enum {DEFAULT_ENUM = DEFAULT};
};


class Val {
 public:
    Val& operator=(const int &val_in) {
        val = val_in;
        return *this;
    }

    int val;
};


typedef Def<int, 10> Def_t;

Val test_val;

int main()
{
    test_val     =       Def_t::DEFAULT_ENUM;  // works
    test_val     =       Def_t::DEFAULT;       // fails to compile
    test_val     = (int) Def_t::DEFAULT;       // works
    test_val.val =       Def_t::DEFAULT;       // works
}
4

1 に答える 1

2

Def_t::DEFAULTコードを定義せずに使用しているため、コードには未定義の動作があります[basic.def.odr]/3:

すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。診断は必要ありません。

クラス定義の宣言は定義ではありません[class.static.data]/2:

クラス定義での静的データ メンバーの宣言は、定義ではありません ... 。静的データ メンバーの定義は、メンバーのクラス定義を囲む名前空間スコープに表示されます。...

の宣言を追加してもコードがコンパイルされない場合Def_t::DEFAULT、これはコンパイラのバグです。名前空間スコープに以下を配置することで、定義を追加できます。

template<typename T, T def>
T const Def<T, def>::DEFAULT;

Tが整数型または列挙型でないときにこれを機能させたい場合はDEFAULT、クラス定義ではなく、この名前空間スコープ定義に初期化子を配置します。

于 2013-04-28T02:33:25.150 に答える