在c++中,是不能用字符串来作为case的标签的,但幸运的是,c++11引入了constexpr和自定义文字常量,将这两个新特性结合,我们实现出看上去像下面这样的代码:

1
2
3
4
5
6
7
8
9
10
string clss = "xxx";
switch (shash_(clss.c_str()))
{
case hash_compile_time("Host"):
break;
case "Sink"_shash: // 对上面hash_compile_time的自定义字面量
break;
case "Switch"_shash:
break;
}

实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typedef unsigned long long hash_t;

constexpr hash_t prime = 0x100000001B3ull;
constexpr hash_t basis = 0xCBF29CE484222325ull;

/// 定义一个hash函数,计算出字符串的hash值,将字符串转换为1个整数
hash_t shash_(char const *str)
{
hash_t ret{basis};

while (*str)
{
ret ^= *str;
ret *= prime;
str++;
}

return ret;
}

/// 利用c++11自定义文字常量的语法,定义一个constexpr函数,switch的case标签处调用这个constexpr函数
constexpr hash_t hash_compile_time(char const *str, hash_t last_value = basis)
{
return *str ? hash_compile_time(str + 1, (*str ^ last_value) * prime)
: last_value;
}

/// 利用自定义文字常量,重载一个operator
constexpr unsigned long long operator"" _shash(char const *p, size_t)
{
return hash_compile_time(p);
}

hash_compile_time函数只有短短的一行,利用递归得到了与上面shash_函数得到的同样值,由于用constexpr声明了函数,因此编译器可以在编译期得出一个字符串的hash值,而这正是关键,既然是编译器就可以得到的整型常量,自然可以放到switch的case标签处了。

转自:https://blog.csdn.net/yozidream/article/details/22789147