NOTE: This is not about using a string for choosing the execution path in a switch-case block.
A common pattern in C++ is to use a switch-case block for converting integer constants to strings. This looks like:
char const * to_string(codes code)
{
switch (code)
{
case codes::foo: return "foo";
case codes::bar: return "bar";
}
}
However, we are in C++, so using std::string is more appropriate:
std::string to_string(codes code)
{
switch (code)
{
case codes::foo: return "foo";
case codes::bar: return "bar";
}
}
This however copies the string literal. Perhaps a better approach would be instead:
std::string const & to_string(codes code)
{
switch (code)
{
case codes::foo: { static std::string str = "foo"; return str; }
case codes::bar: { static std::string str = "bar"; return str; }
}
}
But this is kinda ugly, and involves more boilerplate.
What is considered the cleanest and most efficient solution for this problem using C++14?
You cannot use string in either switch or case .
It is recommended to use String values in a switch statement if the data you are dealing with is also Strings. The expression in the switch cases must not be null else, a NullPointerException is thrown (Run-time). Comparison of Strings in switch statement is case sensitive.
No you can't.
Try this: std::string * sp; std::string func() { std::string s("bla"); sp = &s; return s; } int main() { std::string s = func(); if(sp == &s) std::cout << "YAY"; else std::cout << "BOO"; } -- On my compiler (VS) It prints YAY.
This however copies the string literal.
Yes and no. It will copy the string literal indeed, but don't necessarily allocate memory. Check your implementation SSO limit.
You could use std::string_view
:
constexpr std::string_view to_string(codes code) {
switch (code) {
case codes::foo: return "foo";
case codes::bar: return "bar";
}
}
You can find many backported versions like this one
However, sometimes a char const*
is the right abstraction. For example, if you were to forward that string into an API that require a null terminated string, you'd be better off returning it a c style string.
But this is kinda ugly, and involves more boilerplate.
What is considered the cleanest and most efficient solution for this problem using C++14?
To answer the above, as @SamerTufail pointed out (and as I do it myself at work also), I would use enum
s and std::map
like this.
typedef enum {
foo = 1,
bar = 2,
} Key;
std::map<Key, std::string> hash_map = { {Key::foo ,"foo"}, { Key::bar,"bar"} };
And then in main() you could get the value like this,
std::cout << hash_map.find(Key::foo)->second;
I would create a function for returning the second
, where you would check the iterator for end()
, otherwise the interator would be invalid and using it would be UB.
EDIT: As others have pointed out in the comments and as per this question, you could replace std::map
, with std::unordered_map
provided you do not need to keep elements in order.
And as per my experience, I always create such maps as static const
. Therefore create them one time and use them many times to amortize the cost of creation.
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