如何通过索引访问枚举类?

时间:2018-08-06 02:27:26

标签: c++ template-specialization static-cast enum-class

enum class Fruit { apple, orange, pear };
enum class Color { red, green, orange };

template <typename T> struct Traits;
//I have to return the appropriate value(string) of color and fruit in their respective structs.
//I could do this by switch case method but I specifically wanted to know, how do I access an enum class through index
template<>
struct Traits<Fruit>{
    static string name(int i){
        if(i>-1&&i<3){
            return Fruit::static_cast<Fruit>(i);
        }
        else{
            return "unknown";
        }
    }
};
template<>
struct Traits<Color>{
    static string name(int i){
        if(i>-1&&i<3){
            return Color::static_cast<Color>(i);
        }
        else{
            return "unknown";
        }
    }
};

我想返回相应结构在相应索引处出现的适当字符串。 static_cast无法正常工作,并且编译器给出了无法转换的错误。我不知道是否可以通过索引访问枚举类。

错误:

could not convert ‘(Fruit)i’ from ‘Fruit’ to 
‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’
    return static_cast<Fruit>(i);

2 个答案:

答案 0 :(得分:0)

错误提示您不能直接将enum class转换为字符串。但是您可以使用intenum class转换为static_cast
int转换为enum后,您可以将enum转换为string。有很多方法可以做,this so answer对此做了很好的总结

static string name(int i) {
    if (i>-1 && i<3) {
        Fruit f = static_cast<Fruit>(i);
        return name(f);
    }
    else {
        // return default value or throw error
        return "";
    }
}

static string name(Fruit f) {
    //convert f and return string
}

答案 1 :(得分:0)

您可以在与枚举并行的位置添加一系列水果名称,以使其具有名称:

std::string FruitNames[] = { "apple", "orange", "pear" };

现在,您可以直接使用它来获取名称。如果您愿意对x宏进行一点投资,则可以通过一个宏来生成数组和枚举:

#define FRUITS GEN_FRUIT(apple) GEN_FRUIT(orange) GEN_FRUIT(pear)

#define GEN_FRUIT(X) X,
enum class Fruit { FRUITS };
#undef GEN_FRUIT

#define GEN_FRUIT(X) [Fruit::X] = #X,
std::string const FruitNames[] = { FRUITS };
#undef GEN_FRUIT

另一方面,更难以阅读的是,您只有一个位置可以同时维护枚举数组...

您甚至可以支持显式值:

#define FRUITS GEN_FRUIT_V(apple, 1) GEN_FRUIT(orange) GEN_FRUIT_V(pear, 4)

#define GEN_FRUIT(X) X,
#define GEN_FRUIT_V(X, Y) X = (Y),
enum class Fruit { FRUITS };
#undef GEN_FRUIT
#undef GEN_FRUIT_V

#define GEN_FRUIT(X) GEN_FRUIT_V(X, Fruit::X)
#define GEN_FRUIT_V(X, Y) std::make_pair(static_cast<Fruit>(Y), std::string(#X)),
std::unordered_map<Fruit, std::string> const FruitNames({ FRUITS });
// or (tree) map, if you prefer
//std::map<Fruit, std::string> const FruitNames({ FRUITS });
#undef GEN_FRUIT
#undef GEN_FRUIT_V

在即将发布的C ++ 20(或支持指定初始化程序作为扩展程序的编译器)中,您可以再次使用数组:

#define GEN_FRUIT(X) X,
#define GEN_FRUIT_V(X, Y) X = (Y),
enum class Fruit { FRUITS };
#undef GEN_FRUIT
#undef GEN_FRUIT_V

#define GEN_FRUIT(X) [static_cast<int>(Fruit::X)] = #X,
#define GEN_FRUIT_V(X, Y) GEN_FRUIT(X)
std::string const FruitNames[] = { FRUITS };
#undef GEN_FRUIT
#undef GEN_FRUIT_V

还有未来的音乐...上例中的结果将是一个带有间隙的枚举,并且该阵列在间隙处填充有空字符串。如果差距很大(或存在负的枚举值),那么这种方法也会导致数组较大,因此不再合适,您可能希望再次使用map解决方案...