6

以下是一些枚举类:

enum class Race : char {AINU, ELF, DWARF, MAN, EAGLE, HOBBIT, ENT, ORC, WIZARD};
enum class Color: char {RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE};
enum class Direction: char{UP, DOWN, LEFT, RIGHT};

我想为每个实现一个enum_to_string 函数和一个string_to_enum 函数
将枚举转换为字符串没有问题,因为我可以重载相同的函数名。

std::string to_string(Race const& enum_value);
std::string to_string(Color const& enum_value);
std::string to_string(Direction const& enum_value);

但是,在转换为枚举时不能以相同的方式重载,因为只有返回类型会不同。(我也不想,因为不同的枚举可能用相同的字符串表示。)


以下方法之一可以将字符串转换为枚举吗?

Race race = to_enum<Race>("elf");
Color color = to_enum<Color>("green");

std::string blah{"up"};
Direction dir{to_enum<Direction>(blah)};

或者可能:

Race race = to_enum(Race,"elf");
Color color = to_enum(Color,"green");

std::string blah{"up"};
Direction dir{to_enum(Direction,blah)};

C++ 可以支持其中一种或两种行为吗?


我试图避免像这样的不同函数名称:

Race to_race(std::string const& str);
Color to_color(std::string const& str);
Direction to_direction(std::string const& str);  

这是我能想到的最接近的东西,

template <typename T>struct to_enum{};
template <>
struct to_enum<Color>{

    static Color convert(std::string const& str){
        //match the string with a color enum, and return that color enum
        //(or like a default color enum if the string is garbage or something)
    }
};

然后你这样称呼它:

Color color = to_enum<Color>::convert("red");

我们可以摆脱皈依者吗?或者可能实施这个?

Color color = to_enum(Color,"red");
4

3 回答 3

7

使用功能模板和专业化。这些是我认为功能专业化真正有帮助的罕见情况。

template<typename TEnum>
TEnum enum_cast(std::string const & s);

然后为每个枚举类型专门化它。我更改了名称,因此您可以像 cast 一样阅读它:

Color color = enum_cast<Color>("blue");

或者parse也是一个好名字。选择你认为好的任何东西。我个人会选择parseenum_cast

现在to_string,您可以定义重载(您已经拥有):

std::string to_string(Color c);
std::string to_string(Race r);
std::string to_string(Direction d);

不要对to_string. 一般来说,重载确实很好。

于 2013-01-14T15:24:16.507 回答
4

然后你这样称呼它:

Color color = to_enum<Color>::convert("red");

我们可以摆脱皈依者吗?

确定的事!简单地封装调用:

template <typename Enum>
Enum to_enum(std::string const& from) {
    return to_enum_helper<Enum>::convert(from);
}

to_enum_helper您之前定义的结构在哪里。(编辑:或者您直接将功能专业化,如 Nawaz 的回答所示。)

或者,如果那是您的一杯茶,您可以使用重载而不是专业化:

Race to_enum_helper(std::string const& from, Race) {
    // Implement for enum class Race
}

Color to_enum_helper(std::string const& from, Color) {
    // Implement for enum class Color
}

template <typename Enum>
Enum to_enum(std::string const& from) {
    return to_enum_helper(from, Enum());
}

这里,第二个参数 toto_enum_helper只是用来区分不同的重载。

于 2013-01-14T15:24:47.603 回答
1

但是,在转换为枚举时不能以相同的方式重载,因为只有返回类型会不同。

您可以重载转换运算符来编写仅返回类型不同的重载函数:

#include <string>
#include <iostream>

enum Race {};
enum Color {};

struct to_one_of_them {
    operator Race  () const { std::cout << "to Race()\n"; return Race(); }
    operator Color () const { std::cout << "to Color()\n"; return Color(); }

    to_one_of_them() = delete;

private:
    std::string str;
    to_one_of_them(std::string const &str) : str(str) {}

    friend to_one_of_them to_enum(std::string const&);
};

to_one_of_them to_enum(std::string const &str) {
    return {str};
}


int main () {
    Race  r = to_enum("meh");
    Color c = to_enum("meh");
}

然而,这种技术实际上没有被使用,因此不是 C++ 习惯用法,因此可能不值得学习。

于 2013-01-14T15:55:55.157 回答