众所周知,C/C++ 语言中的 switch
-case
语句只支持整型数字的逻辑分支。因此,当我们需要对整型数字之外的变量进行分支判断时,就只能依赖 if
-else
语句了。例如:
1 | if (policy == "SINGLE") { |
这种情况下,虽然我们用 if
-else
语句实现了类似 switch
-case
语句的功能。但一方面写起来未免麻烦,分支多了难以维护;另一方面如果分支很多,那么执行起来需要注意进行字符串相等性判断,效率很低。因此,这篇文章尝试通过一些取巧的方式来解决这个问题。
HASH
无论如何,语言层面的 swtch
-case
限制是绕不开的。因此,我们需要找到一个有效的办法,将字符串与整形数字对应起来。虽然不甚完美,但是 Hash 是一种解决办法。于是我们针对 C 风格的字符串定义 Hash 函数。
1 | using hash_t = size_t; |
如此,我们「似乎」便可以针对字符串使用 switch
-case
语句了。
1 | void simple_switch(const char* str) { |
constexpr
函数
然而,如果你编译这段代码,编译器就会提醒你在 case
处必须使用常量表达式。因此,对于 case
的分支选项,我们不仅要将他们转换为整型 hash_t
,还必须保证它们在编译期就能运算完成,从而作为常量表达式。考虑到,在 C++11 中常量表达式函数必须只能有一个 return
语句(在 C++14 之后就没有这个限制了),因此我们需要借助 C++ 中的三元运算符 ?:
将 hash_run_time
函数改造为递归形式。
1 | constexpr hash_t hash_compile_time(const char* str, hash_t last_value = basis) { |
同时,simple_switch
函数也需要改造一下:
1 | void simple_switch(const char* str) { |
此时,simple_switch
函数已可通过编译。
事实上,用于处理输入的
hash_run_time
也可以被hash_compile_time
替代。
用户定义的字面值常量后缀
尽管此时代码已经可以通过编译并使用,但在每个 case
处都写一个函数调用未免麻烦。于是我们需要引入用户定义的字面值常量后缀(User-defined suffix)简化代码。
1 | constexpr hash_t operator "" _hash(const char* p, size_t) { |
于是,simple_switch
函数可被简化为:
1 | void simple_switch(const char* str) { |
完整的测试代码可见:https://gist.github.com/25dcb10e55b3cb2306931aa277355bbf。