Here are some enum classes:
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};
I would like to implement an enum_to_string function and a string_to_enum function for each.
It's no problem converting enums into strings, because I can overload the same function name.  
std::string to_string(Race const& enum_value);
std::string to_string(Color const& enum_value);
std::string to_string(Direction const& enum_value);
However, you can't overload the same way when converting to enums, because only the return-type would be different. (nor would I want to, because different enums may be represented by the same string.)
Are one of the following ways possible for converting strings into enums?
Race race = to_enum<Race>("elf");
Color color = to_enum<Color>("green");
std::string blah{"up"};
Direction dir{to_enum<Direction>(blah)};
or possibly:
Race race = to_enum(Race,"elf");
Color color = to_enum(Color,"green");
std::string blah{"up"};
Direction dir{to_enum(Direction,blah)};
Can C++ support one or both of these behaviours?
I'm trying to avoid different function names like this:
Race to_race(std::string const& str);
Color to_color(std::string const& str);
Direction to_direction(std::string const& str);  
Here is the closest thing I could come up with,
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)
    }
};
and then you call it like this:
Color color = to_enum<Color>::convert("red");
can we get rid of the convert? or possibly implement this one?
Color color = to_enum(Color,"red");
                Use function template and specialization. These are rare situations where I think function specialization really helps.
template<typename TEnum>
TEnum enum_cast(std::string const & s);
then specialize it for each enum type. I changed the name, so you can read it like cast:
Color color = enum_cast<Color>("blue");
Or parse is also a good name.  Choose whatever you think is good. I would personally choose either parse or enum_cast.
Now for to_string, you can define overloads (which you already have):
std::string to_string(Color c);
std::string to_string(Race r);
std::string to_string(Direction d);
Don't use template and specialization for to_string. Overloads are indeed good in general.
and then you call it like this:
Color color = to_enum<Color>::convert("red");can we get rid of the convert?
Sure thing! Simply encapsulate the call:
template <typename Enum>
Enum to_enum(std::string const& from) {
    return to_enum_helper<Enum>::convert(from);
}
Where to_enum_helper is the struct you defined previously. (EDIT: Or you specialise the function directly as shown in Nawaz’ answer.)
Alternatively, you can use overloading instead of specialisation if that’s your cup of tea:
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());
}
Here, the second argument to to_enum_helper is simply used to distinguish the different overloads.
However, you can't overload the same way when converting to enums, because only the return-type would be different.
You could overload conversion operators to write overload functions that differ only by 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");
}
However, this technique is virtually unused and therefore not a C++ idiom and thus probably not worth to learn.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With