c++ 11类型到枚举的映射

C++11 type to enum mapping?

本文关键字:映射 枚举 类型 c++      更新时间:2023-10-16

我有一个enum:

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'

最好的方法是什么?为什么会出现错误?

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

ODR(单定义规则)声明

(§3.2/2)[…如果变量名出现在潜在求值表达式中,则不建议使用,除非它是一个对象,满足出现在常量表达式中(5.19)的要求,并且立即应用左值到右值的转换(4.1)。[…]

(然后,许多特殊的规则,例外和例外的例外。)

任何奇数使用的变量,必须只有一个定义。你的常量表达式有一个声明,但没有定义,所以这很好,除非你经常使用其中一个。

例如:

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

但这不是:

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

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

(备注。正如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;
}

静态成员变量需要在类作用域之外定义:

class C {
    const static int x = 5;
};
decltype(C::x) C::x;

可能是因为您忘记在enum定义后放置分号,这在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