C ++ 11类型到枚举映射?

时间:2013-02-27 13:35:42

标签: c++ c++11 constexpr

我有一个类似的枚举:

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'

这是最好的方法吗?为什么错误?

3 个答案:

答案 0 :(得分:6)

这取决于你如何使用这些常量表达式。

ODR(单一定义规则)声明

  

(§3.2/ 2)[...]一个名称显示为潜在评估表达式的变量是odr-used,除非它是一个满足出现在常量表达式(5.19)和左值的要求的对象立即应用到右值转换(4.1)。 [...]

(然后,许多特殊规则,例外情况和异常例外如下。)

odr-used的任何变量必须只有一个定义。你的常量表达式有一个声明,但不是一个定义,所以这很顺利,除非你使用其中一个。

例如,以下情况很顺利:

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

但这不是:

void f(const E &)
{ }

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

因为f需要(const)引用,所以不能立即应用左值到右值的转换,因此这构成了一个使用odr。编译器会抱怨它错过了一个定义。

(注意。正如ShafikYaghmour发现的那样(参见评论),如果编译器使用优化,您可能不会抱怨,因为引用可能会被优化掉。要重现编译器投诉,请使用-O0标志(或类似的,取决于编译器。)

要解决此问题,可以通常的方式提供所需的定义,即在结构定义之外:

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

但是由于这必须发生在.cpp(而不是头文件)中,所以最终必须在两个不同的地方维护声明和定义,这很麻烦。

您刚才在评论中提出的解决方案,即定义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 :(得分:1)

静态成员变量需要在类范围之外定义

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

decltype(C::x) C::x;

答案 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

的链接