5

私は次のような列挙型を持っています:

enum E
{
    TYPE_FLOAT,
    TYPE_CHAR,
    TYPE_INT
}

そして、コンパイル時のマッピングを作成して、次のような型に適切な E を取得したいと考えています。

GetE<float> // returns TYPE_FLOAT
GetE<char> // returns TYPE_CHAR
GetE<int> // returns 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; };

しかし、次のようなエラーが発生します。

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

これを行う最良の方法は何ですか?そして、なぜエラーですか?

4

3 に答える 3

6

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

ODR (1 定義規則) は、次のように述べています。

(§3.2/2) [...] 潜在的に評価される式として現れる名前を持つ変数は、それが定数式 (5.19) および左辺値に現れるための要件を満たすオブジェクトでない限り、odr-used です。右辺値変換 (4.1) がすぐに適用されます。[...]

(そして、多くの特別なルール、例外、および例外の例外が続きます。)

ODR で使用される変数に、正確に 1 つの定義が必要です。あなたの定数式には宣言がありますが、定義はありません。

たとえば、次のようにするとうまくいきます。

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

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

void f(const E &)
{ }

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

(const) 参照が必要なためf、左辺値から右辺値への変換をすぐに適用することはできません。したがって、これは ODR 使用を構成します。コンパイラは、定義が欠落していると文句を言います。

(注。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;
}
于 2013-02-27T13:50:11.537 に答える
1

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

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

decltype(C::x) C::x;
于 2013-02-27T13:42:48.617 に答える
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

于 2013-02-27T13:42:59.657 に答える