2013-02-27 19 views
5

私のような列挙型があります。C++ 11型から列挙型マッピングへ?

enum E 
{ 
    TYPE_FLOAT, 
    TYPE_CHAR, 
    TYPE_INT 
} 

をそして私のようなタイプのために適切なEを取得するために、コンパイル時のマッピングを作成します:

template<class T> struct GetE; 

template<> struct GetE<float> { static constexpr E type = TYPE_FLOAT; }; 
template<> struct GetE<char> { static constexpr E type = TYPE_CHAR; }; 
template<> struct GetE<int> { static constexpr E type = TYPE_INT; }; 
:私は考え

GetE<float> // returns TYPE_FLOAT 
GetE<char> // returns TYPE_CHAR 
GetE<int> // returns TYPE_INT 

でも、次のようなエラーが表示されます。

undefined reference to `GetE<int>::type' 

これを行うにはどうすればよいですか?そしてなぜそのエラー?

答えて

6

これはどのように使用するかによって異なります定数式。

ODR(ワン定義ルール)は、それがない限り、名前潜在的評価式として現れる

(§3.2/ 2)[...]変数はODR-使用されていることを述べて定数式(5.19)と左辺値 - 右辺値変換(4.1)で出現するための要件を満たすオブジェクトが直ちに適用されます。 [...]

(そして、特別な規則がたくさん、例外の例外と例外は以下の通り。)

が使用ODR-であることを、任意の変数、正確に一つの定義を持っている必要があります。あなたの定数式には宣言がありますが、定義はありません。したがって、あなたがそれらのうちの1つをodr-useしなければうまくいきます。

たとえば、次のようにうまく行く:

int main() { 
    E e = GetE<float>::type; 
    return 0; 
} 

しかし、これはしていません:

void f(const E &) 
{ } 

int main() { 
    f(GetE<float>::type); 
    return 0; 
} 

fは(定数)の参照が必要なので、左辺値ツー右辺値の変換ができないため、すぐに適用されるので、これはodr-useを構成します。コンパイラは、定義が不足していると不満を持ちます。

(備考ShafikYaghmourが見つかった(コメントを参照)ので、コンパイラが最適化を使用している場合に苦情を受け取ることはできません。コンパイラの苦情を再現するには、-O0フラグコンパイラによって異なります)。

この問題を解決するために、必要な定義を通常の方法で提供することができます。

constexpr E GetE<float>::type; 
constexpr E GetE<char>::type; 
constexpr E GetE<int>::type; 

しかし、これは.cppファイル(ないヘッダファイル)で発生しなければならないことから、あなたがある、2つの異なる場所での宣言と定義を維持するために持ってしまいます:構造体、定義の外面倒です。

あなたは自分のコメントで提案しました解決策、すなわち、constexprの(インライン)関数を定義し、右に聞こえる:

template <class T> constexpr E GetE(); 

template <> constexpr E GetE<float>() 
{ return TYPE_FLOAT; } 

template <> constexpr E GetE<char>() 
{ return TYPE_CHAR; } 

template <> constexpr E GetE<int>() 
{ return TYPE_INT; } 

void f(const E &) 
{ } 

int main() { 
    E e = GetE<float>(); 

    f(GetE<float>()); 

    return 0; 
} 
+1

これは妥当と聞こえます。私は 'tmpl E GetE()'のような関数テンプレートを使い、その代わりにそれを専門にするように変更しました。これはそれを修正しました。ありがとう。 –

+1

@jogojapanあなたのコメントから勉強しようとしていますが、最後のコードを使用してエラーが表示されません:http://liveworkspace.org/code/4oTEis何が欠けていますか? –

+1

@ShafikYaghmour '-O2'コンパイラフラグが原因です。参照を最適化します。良いコメントですが、答えに言及します。 – jogojapan

1

静的メンバ変数はは、クラスのスコープ外を定義する必要があります。たぶん

class C { 
    const static int x = 5; 
}; 

decltype(C::x) C::x; 
+0

でもその 'constexpr'か?それは変だ。 –

+0

GCC 4.7では動作します。たぶんそれはあなたのコンパイラでしょうか? –

+0

4.7.2も使用してください。 –

1

あなたが列挙型定義の後にセミコロンを置くことを忘れてしまったので、これはLiveWorkSpaceで私の作品:

#include <iostream> 

enum E 
{ 
    TYPE_FLOAT, 
    TYPE_CHAR, 
    TYPE_INT 
} ; 

template<class T> struct GetE; 

template<> struct GetE<float> { static constexpr E type = TYPE_FLOAT; }; 
template<> struct GetE<char> { static constexpr E type = TYPE_CHAR; }; 
template<> struct GetE<int> { static constexpr E type = TYPE_INT; }; 

int main() 
{ 
    std::cout << GetE<int>::type << std::endl ; 
} 

ここにコードへのリンクがありますhttp://liveworkspace.org/code/nHqUe $ 6

+0

実際のコードにはセミコロンはありません。うーん、奇妙。私も4.7.2を使っています。何が起こっているかわからない。ありがとう。 –