Reputation: 6745
Is there a simple way in C++ to convert a string to an enum (similar to Enum.Parse
in C#)? A switch statement would be very long, so I was wondering if there is a simpler way to do this?
EDIT:
Thanks for all of your replies. I realized that there was a much simpler way to do it for my particular case. The strings always contained the charater 'S' followed by some number so i just did
int i = atoi(myStr.c_str() + 1);
and then did a switch on i.
Upvotes: 38
Views: 156992
Reputation: 4737
You will have to map the string values (chain of characters) to a corresponding enum value (integer). Here's how you would do this in practice using std::map
:
#include <cstdio>
#include <map>
#include <string_view>
#include <stdexcept>
enum class myenum
{
content_encoding,
content_length,
transfer_encoding,
};
// In C++23 use a constexpr flat_map instead
const std::map<std::string_view, myenum> map_myenum = {
{"content-encoding", myenum::content_encoding},
{"content-length", myenum::content_length},
{"transfer-encoding", myenum::transfer_encoding},
};
auto test(std::string_view str)
{
try {
switch(map_myenum.at(str)) {
case myenum::content_encoding:
printf("String was content_encoding\n");
break;
case myenum::content_length:
printf("String was content_length\n");
break;
case myenum::transfer_encoding:
printf("String was transfer_encoding\n");
break;
}
} catch(const std::out_of_range& e) {
printf("String didn't match any criteria!\n");
}
}
int main()
{
test("content-encoding");
test("content-length");
test("some random other stuff");
}
Output:
String was content_encoding
String was content_length
String didn't match any criteria!
A few notes:
.at()
method as it doesn't insert items if it doesn't find the key in the map. It's a bit of an unfortunate decision by the CWG in my view, as this is definitely nothing "exceptional" and we shouldn't have to pay the cost (in this case at least).Upvotes: 0
Reputation: 423
I use this "trick" > http://codeproject.com/Articles/42035/Enum-to-String-and-Vice-Versa-in-C
After
enum FORM {
F_NONE = 0,
F_BOX,
F_CUBE,
F_SPHERE,
};
insert
Begin_Enum_String( FORM )
{
Enum_String( F_NONE );
Enum_String( F_BOX );
Enum_String( F_CUBE );
Enum_String( F_SPHERE );
}
End_Enum_String;
It works fine, if the values in the enum are not duplicates.
Example in code
enum FORM f = ...
const std::string& str = EnumString< FORM >::From( f );
vice versa
assert( EnumString< FORM >::To( f, str ) );
Upvotes: 7
Reputation: 308081
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() }
Upvotes: 56
Reputation: 11
"Additional question: Is it possibile to handle undefined strings ? I mean if I try to get the value for responseHeaderMap["cookie"], what will be the value? (provided that "cookie" is not defined in the responseHeaderMap – bart s Nov 22 '16 at 12:04"
well, you can just make check before:
auto it = responseHeaderMap.find("cookie");
if (it != responseHeaderMap.end())
{
// "cookie" exist, can take value
}
After "cookie" exist check, you can get it value with use:
responseHeaderMap["cookie"]
hope this help
Upvotes: 0
Reputation: 2954
saw this example somewhere
#include <map>
#include <string>
enum responseHeaders
{
CONTENT_ENCODING,
CONTENT_LENGTH,
TRANSFER_ENCODING,
};
// String switch paridgam
struct responseHeaderMap : public std::map<std::string, responseHeaders>
{
responseHeaderMap()
{
this->operator[]("content-encoding") = CONTENT_ENCODING;
this->operator[]("content-length") = CONTENT_LENGTH;
this->operator[]("transfer-encoding") = TRANSFER_ENCODING;
};
~responseHeaderMap(){}
};
Upvotes: 14
Reputation: 1751
this worked for me:
enum NODES { Cone = 1, BaseColor = 2, NONE = 0 };
std::map<std::string, NODES> nodeMap;
nodeMap["Cone"] = NODES::Cone;
nodeMap["BaseColor"] = NODES::BaseColor;
Upvotes: 8
Reputation: 5665
There is no "built-in way", but there are ways to achieve this by storing the pair value-name in an array
enum myEnum
{
enumItem0,
enumItem1,
enumItem7 = 7,
enumItem8
};
std::vector<std::pair<myEnum,std::string>> gMap;
#define ADDITEM(x) gMap.push_back(std::pair<myEnum,std::string>(x,#x));
.....
ADDITEM(enumItem0);
ADDITEM(enumItem1);
ADDITEM(enumItem7);
ADDITEM(enumItem8);
Upvotes: 6
Reputation: 16578
No, you'll have to use an if/then construction, or use a map or hash table or some other type of associative data structure to facilitate this.
Upvotes: 0
Reputation: 155
You can use macro to minimize repeating yourself. Here is the trick: Enums, Macros, Unicode and Token-Pasting
Upvotes: 2
Reputation: 714
While there is no direct solution, there are a few possible workarounds.
Take a look at this question: Easy way to use variables of enum types as string in C?
Upvotes: 2
Reputation: 361264
Use std::map<std::string, Enum>
and use boost::map_list_of
to easily initialize it.
Example,
enum X
{
A,
B,
C
};
std::map<std::string, X> xmap = boost::map_list_of("A", A)("B", B)("C",C);
Upvotes: 27
Reputation: 3563
It is not possible because the names are not available at runtime. During compilation each enum is replaced with the corresponding integer value.
Upvotes: 2
Reputation: 35039
In short: there is none. In C++ enums are static values and not objects like in C#. I suggest you use a function with some if else
statements.
Upvotes: 4