有時候,我們想寫出下面這樣的switch語句:
const char* str = "first";
switch(str){
case "first":
cout << "1st one" << endl;
break;
case "second":
cout << "2nd one" << endl;
break;
case "third":
cout << "3rd one" << endl;
break;
default:
cout << "Default..." << endl;
}
但是在c++中,是不能用字符串來作爲case的標籤的;於是,很疑惑,我們只能用其他的辦法來實現這樣的需求。
但幸運的是,c++11引入了constexpr和自定義文字常量,將這兩個新特性結合,我們實現出看上去像上面這樣的代碼。
基本思路爲:
1、定義一個hash函數,計算出字符串的hash值,將字符串轉換爲1個整數;
typedef std::uint64_t hash_t;
constexpr hash_t prime = 0x100000001B3ull;
constexpr hash_t basis = 0xCBF29CE484222325ull;
hash_t hash_(char const* str)
{
hash_t ret{basis};
while(*str){
ret ^= *str;
ret *= prime;
str++;
}
return ret;
}
2、利用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;
}
這個函數只有短短的一行,利用遞歸得到了與上面hash_函數得到的同樣值,由於用constexpr聲明瞭函數,因此編譯器可以在編譯期得出一個字符串的hash值,而這正是關鍵,既然是編譯器就可以得到的整型常量,自然可以放到switch的case標籤處了。
於是我們可以寫出這樣的swich語句:
void simple_switch2(char const* str)
{
using namespace std;
switch(hash_(str)){
case hash_compile_time("first"):
cout << "1st one" << endl;
break;
case hash_compile_time("second"):
cout << "2nd one" << endl;
break;
case hash_compile_time("third"):
cout << "3rd one" << endl;
break;
default:
cout << "Default..." << endl;
}
}
這個實現中,hash_compile_time("first")是編譯器計算出來的一個常量,因此可以用作case標籤;而且如果出現了hash值衝突,編譯器回給出錯誤提示。
3、上面的語法還不夠漂亮,利用自定義文字常量,重載一個operator如下:
constexpr unsigned long long operator "" _hash(char const* p, size_t)
{
return hash_compile_time(p);
}
現在我們可以寫這樣的文字常量,用“_hash”作爲自定義文字常量的後綴,編譯器看到這個後綴結尾的文字常量,就會去調用我們重載的operator,得到和調用hash_compile_time是一樣的值,但看起來舒服多了:
"first"_hash
現在,我們寫出的switch語句就好看多了。
void simple_switch(char const* str)
{
using namespace std;
switch(hash_(str)){
case "first"_hash:
cout << "1st one" << endl;
break;
case "second"_hash:
cout << "2nd one" << endl;
break;
case "third"_hash:
cout << "3rd one" << endl;
break;
default:
cout << "Default..." << endl;
}
}
————————————————
版權聲明:本文爲CSDN博主「YoziDream」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yozidream/article/details/22789147