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);

ただし、列挙型に変換するときに同じ方法でオーバーロードすることはできません。これは、return-typeのみが異なるためです。(異なる列挙型が同じ文字列で表される可能性があるため、私もそうしたくありません。)


文字列を列挙型に変換するには、次のいずれかの方法が可能ですか?

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);

次に、列挙型ごとに特殊化します。名前を変更したので、キャストのように読むことができます。

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

またはparse、良い名前でもあります。あなたが良いと思うものを選んでください。私は個人的にまたはのいずれかを選択しparseますenum_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());
}

ここで、の2番目の引数to_enum_helperは、さまざまなオーバーロードを区別するために使用されています。

于 2013-01-14T15:24:47.603 に答える
1

ただし、列挙型に変換するときに同じ方法でオーバーロードすることはできません。これは、return-typeのみが異なるためです。

変換演算子をオーバーロードして、戻り値のタイプのみが異なるオーバーロード関数を作成できます。

#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 に答える