String to Enum in C++

Converting from String to Enum in C

The standard way to implement it is something along the lines of:

typedef enum {value1, value2, value3, (...) } VALUE;

const static struct {
VALUE val;
const char *str;
} conversion [] = {
{value1, "value1"},
{value2, "value2"},
{value3, "value3"},
(...)
};

VALUE
str2enum (const char *str)
{
int j;
for (j = 0; j < sizeof (conversion) / sizeof (conversion[0]); ++j)
if (!strcmp (str, conversion[j].str))
return conversion[j].val;
error_message ("no such string");
}

The converse should be apparent.

How to convert enum names to string in c

One way, making the preprocessor do the work. It also ensures your enums and strings are in sync.

#define FOREACH_FRUIT(FRUIT) \
FRUIT(apple) \
FRUIT(orange) \
FRUIT(grape) \
FRUIT(banana) \

#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,

enum FRUIT_ENUM {
FOREACH_FRUIT(GENERATE_ENUM)
};

static const char *FRUIT_STRING[] = {
FOREACH_FRUIT(GENERATE_STRING)
};

After the preprocessor gets done, you'll have:

enum FRUIT_ENUM {
apple, orange, grape, banana,
};

static const char *FRUIT_STRING[] = {
"apple", "orange", "grape", "banana",
};

Then you could do something like:

printf("enum apple as a string: %s\n",FRUIT_STRING[apple]);

If the use case is literally just printing the enum name, add the following macros:

#define str(x) #x
#define xstr(x) str(x)

Then do:

printf("enum apple as a string: %s\n", xstr(apple));

In this case, it may seem like the two-level macro is superfluous, however, due to how stringification works in C, it is necessary in some cases. For example, let's say we want to use a #define with an enum:

#define foo apple

int main() {
printf("%s\n", str(foo));
printf("%s\n", xstr(foo));
}

The output would be:

foo
apple

This is because str will stringify the input foo rather than expand it to be apple. By using xstr the macro expansion is done first, then that result is stringified.

See Stringification for more information.

String to enum in C++

You can set up a map that you can use over and over:

template <typename T>
class EnumParser
{
map <string, T> enumMap;
public:
EnumParser(){};

T ParseSomeEnum(const string &value)
{
map <string, T>::const_iterator iValue = enumMap.find(value);
if (iValue == enumMap.end())
throw runtime_error("");
return iValue->second;
}
};

enum SomeEnum
{
Value1,
Value2
};
EnumParser<SomeEnum>::EnumParser()
{
enumMap["Value1"] = Value1;
enumMap["Value2"] = Value2;
}

enum OtherEnum
{
Value3,
Value4
};
EnumParser<OtherEnum>::EnumParser()
{
enumMap["Value3"] = Value3;
enumMap["Value4"] = Value4;
}

int main()
{
EnumParser<SomeEnum> parser;
cout << parser.ParseSomeEnum("Value2");
}

Convert a string to an enum in C#

In .NET Core and .NET Framework ≥4.0 there is a generic parse method:

Enum.TryParse("Active", out StatusEnum myStatus);

This also includes C#7's new inline out variables, so this does the try-parse, conversion to the explicit enum type and initialises+populates the myStatus variable.

If you have access to C#7 and the latest .NET this is the best way.

Original Answer

In .NET it's rather ugly (until 4 or above):

StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);

I tend to simplify this with:

public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}

Then I can do:

StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");

One option suggested in the comments is to add an extension, which is simple enough:

public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}

StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();

Finally, you may want to have a default enum to use if the string cannot be parsed:

public static T ToEnum<T>(this string value, T defaultValue) 
{
if (string.IsNullOrEmpty(value))
{
return defaultValue;
}

T result;
return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

Which makes this the call:

StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

However, I would be careful adding an extension method like this to string as (without namespace control) it will appear on all instances of string whether they hold an enum or not (so 1234.ToString().ToEnum(StatusEnum.None) would be valid but nonsensical) . It's often be best to avoid cluttering Microsoft's core classes with extra methods that only apply in very specific contexts unless your entire development team has a very good understanding of what those extensions do.

Is there a way to use an enum for characters in a string? C++

2) I know it's possible to do with a unordered_map but I think enums
is much quicker.

you're comparing oranges with apples.

first, enum is not a container. it's basically just like a list of known constants.

when you mean the access time of operator[]:

for unordered_map:

Unordered map is an associative container that contains key-value
pairs with unique keys. Search, insertion, and removal of elements
have average constant-time complexity.

for string it's also constant time access.

1) Is using enum with a string possible

No. An enum key is basically like an "alias" for the value. Note that each string is a sequence of characters:

V != "V"

C++ string to enum

A std::map<std::string, MyEnum> (or unordered_map) could do it easily. Populating the map would be just as tedious as the switch statement though.

Edit: Since C++11, populating is trivial:

static std::unordered_map<std::string,E> const table = { {"a",E::a}, {"b",E::b} };
auto it = table.find(str);
if (it != table.end()) {
return it->second;
} else { error() }

enum to string in modern C++11 / C++14 / C++17 and future C++20

Magic Enum header-only library provides static reflection for enums (to string, from string, iteration) for C++17.

#include <magic_enum.hpp>

enum Color { RED = 2, BLUE = 4, GREEN = 8 };

Color color = Color::RED;
auto color_name = magic_enum::enum_name(color);
// color_name -> "RED"

std::string color_name{"GREEN"};
auto color = magic_enum::enum_cast<Color>(color_name)
if (color.has_value()) {
// color.value() -> Color::GREEN
};

For more examples check home repository https://github.com/Neargye/magic_enum.

Where is the drawback?

This library uses a compiler-specific hack (based on __PRETTY_FUNCTION__ / __FUNCSIG__), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 9.

Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX].

  • By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128.

  • If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX.

  • MAGIC_ENUM_RANGE_MIN must be less or equals than 0 and must be greater than INT16_MIN.

  • MAGIC_ENUM_RANGE_MAX must be greater than 0 and must be less than INT16_MAX.

  • If need another range for specific enum type, add specialization enum_range for necessary enum type.

    #include <magic_enum.hpp>

    enum number { one = 100, two = 200, three = 300 };

    namespace magic_enum {
    template <>
    struct enum_range<number> {
    static constexpr int min = 100;
    static constexpr int max = 300;
    };
    }


Related Topics



Leave a reply



Submit