C++ can’t have strings (or string literals) in switch-expressions as case
values.
There can only be constant integral values or enum values (an enum itself is an integer type secretly).
Such a strict restriction is made for practical reasons - switch expressions in executable code can be transformed into a super-optimized form using branch table, when the integer value of the argument simply calculates the address of the code to jump to.
It is clear that it is impossible to make branch tables for strings, so the efficiency of such a switch will not differ from a bunch of if-expressions.
In other programming languages, strings in switch are possible: Java 7, C# 6, but these languages do not focus on maximum performance.
But you can make a self-written simple “switch” to simplify this code:
1
2
3
4
5
6
7
8
9
10
11
12
Color color = UnknownColor;
if (argv[i] == "red") {
color = Red;
} else if (argv[i] == "orange") {
color = Orange;
} else if (argv[i] == "yellow") {
color = Yellow;
} else if (argv[i] == "green") {
color = Green;
} else if (argv[i] == "violet" || argv[i] == "purple") {
color = Violet;
}
into this:
1
2
3
4
5
6
7
Color color = StringSwitch<Color>(argv[i])
.Case("red", Red)
.Case("orange", Orange)
.Case("yellow", Yellow)
.Case("green", Green)
.Cases("violet", "purple", Violet)
.Default(UnknownColor);
There is a StringSwitch
realization in llvm: StringSwitch.h.
This class has just two fields:
std::string_view str
- the string (argv[i]
in our case)std::optional<T> value
- the resulting value (in our caseT == Color
)
When calling the Case method, if value
is not set yet and the given string equals to str
, then value
is set.
There are EndsWith and StartsWith methods which will fill value
if a part of str
equals to the given string.
There are corresponding case-insensitive methods, as well as Case methods for multiple values.
Finally there is a conversion operator (in our case it converts to Color
).
In my opinion, one can also make a LambdaSwitch
class, which, unlike StringSwitch
, should accept lambdas, and set a value if the given lambda returns true. 🙂