1. 程式人生 > >C++11新特性,實現用字串作為switch的case子句

C++11新特性,實現用字串作為switch的case子句

有時候,我們想寫出下面這樣的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

相關推薦

C++11特性實現字串作為switch的case子句

有時候,我們想寫出下面這樣的switch語句: const char* str = "first";  switch(str){  case "first":  cout << "1st one" << endl; 

C++11特性bind基於對象

實體 oca jci con data () ebr mrp ddd body, table{font-family: 微軟雅黑; font-size: 10pt} table{border-co

C++11特性應用--實現延時求值(std::function和std::bind)

說是延時求值,注意還是想搞一搞std::function和std::bind。 現在就算是補充吧,再把std::bind進行討論討論。 何為Callable Objects? 即可呼叫物件,比如函式指標、仿函式、類成員函式指標等都可稱為可呼叫物件。

C++11特性(66)- static_cast將左值轉換為右值

溫故而知新 本文涉及兩個概念,static_cast和右值引用,在閱讀本文之前,最好先閱讀下面的文章。 使用std::move 考察下面兩個函式: 除了引數型別一個是左值引用,一個是右值引用以外都一樣。結合前面的文章可以得出下面的結論:左值引用表明這個

C++11特性應用--介紹幾個新增的便利算法(用於排序的幾個算法)

uil pretty processor nes container 升序 .text mar c++11 繼續C++11在頭文件algorithm中添加的算法。 至少我認為,在stl的算法中,用到最多的就是sort了,我們不去探索sort的源代碼。就

C++11特性之 std::forward(完美轉發)(轉)

tails array sin .com std utili res details calling 我們也要時刻清醒,有時候右值會轉為左值,左值會轉為右值。 (也許“轉換”二字用的不是很準確) 如果我們要避免這種轉換呢? 我們需要一種方法能按照參數原來的類型轉發到另一個函

C++11特性——lambda表達式

amp 多個 str exp href 似的 exception 定義 參數傳遞 C++11的一大亮點就是引入了Lambda表達式。利用Lambda表達式,可以方便的定義和創建匿名函數。對於C++這門語言來說來說,“Lambda表達式”或“匿名函數”這些概念聽起來好像很深奧

C++11特性(87)-專題文章彙總

寫在最後   本連載從去年10月29日開始,到今天就全部結束了。為了方便各位讀者更加方便地利用這些文章,特將本連載的文章連結彙總到一個檔案中。歡迎大家多加利用。   歡迎大家繼續關注本公眾號!   文章下載連結: https://down

C++11特性(86)-類型別的union成員(2)

經過一番準備,我們進入正題。   類型別的union成員 C++的早期版本不允許union的成員是定義了建構函式或拷貝控制成員的類型別成員,C++11中取消了這個限制。但是也別高興得太早,因為這類union在發生涉及到類型別成員的值轉換時需要根據需求呼叫相關類成員的建構函式

C++11特性(85)-類型別的union成員(1)

接下來的兩篇文章介紹C++11的最後一個新特性:類型別的union成員。這個新特性涉及的內容較多,所以本文先做一些不屬於C++11新特性的準備工作。   匿名union 我們通過一個例子類說明。假設有以下函式: 這 個函式的功能是根據引數rt的要求產生隨機數

C++11特性(84)-標準庫mem_fn類模板

定製演算法 演算法是C++標準庫中非常重要的部分,C++通過演算法+容器的方式將資料結構和演算法進行了分離。這樣做的好處就是使使用者獲得最大限度的靈活性。   例如下面的Tracer類。 我們可以非常方便的定義儲存Tracer物件的資料結構:  

C++11特性(83)-enum前置宣告

大型開發都會遇到的問題 隨著軟體規模的擴大,包含在一個工程中的模組的數量在不斷增長,模組之間的依賴關係也日益複雜。這裡只舉一個相對簡單的例子:一個包含2個類,5個檔案的工程。 ImportantClass.h 標頭檔案中聲明瞭建構函式,doWork成員函式和資料成員buffer

C++11特性(82)-指定enum型別的大小

enum型別有多大? 這並不是一個簡單的問題,需要分情況討論。   沒有指定作用域的情況 列舉型別的大小會隨著列舉值的範圍自動調整。例如下面的程式碼: enum_1只有兩個列舉值,它的大小就是4個位元組;enum_2的第一個列舉值指定了一個超過32位的數,所以

C++11特性(81)-有作用域的enum(scoped enumeration)

列舉型別的困惑 從C語言過度到C++以後,列舉作為減少程式錯誤的手段之一被廣泛地使用。但是同時也帶來一個問題:列舉值的重複。假設我們有下面的三原色定義: 程式碼中同時也需要定義三基色: 二者同時定義之後,就會遇到一個問題:red和blue連個值都被重複定義。 &nbs

C++11特性(80)-繼承的建構函式與多重繼承

複習 本文算是前面文章的繼續。 對於繼承的建構函式,C++11通過一個簡單的using語句,使得繼承一個類時可以省去一些麻煩。具體可以參照下面的文章。 C++11新特性(59)-繼承的建構函式 https://mp.weixin.qq.com/s/BGUa7-RSCtFRnBYj

C++11特性(79)-內聯名稱空間(inline namespace)

名稱空間簡介 隨著軟體開發規模的擴大,類名,函式名重複的可能性也越來越大。最樸素的解決辦法就是改名,這種方法在向已經存在的類庫中新增程式碼時問題不大,但是如果是將兩個從未謀面的程式碼庫結合在一起時就不再適用了。 C++解決這個問題的辦法就是引入名稱空間。假設有下面兩個名稱空間:

C++11特性(78)-noexcept運算子(noexcept operator)

前一篇文章說明了noexcept說明符,使用了該說明符就相當於對程式設計師和編譯器雙方承諾不會丟擲異常。程式設計師看到這個承諾,可以不必編寫複雜的異常捕捉程式碼;編譯器看到這個承諾,可以執行某些可能丟擲異常時無法進行的優化操作。 異常符說明的實參 前一篇文章沒有提到,實際上noexcep

C++11特性(77)-noexcept異常指示符(Exception Specifier)

C++異常處理 異常處理(exception handing)使問題的檢測和處理過程可以分別進行,是C++適用於大規模開發的重要語言特性之一。首先進行簡單說明。 首先假設我們有丟擲某種Error的函式testfun()。   注意:C++並不要求丟擲的物件一定是e

C++11特性(76)-浮點數格式控制(Floating Format Control)

前幾篇文章中的某一篇,有一個讀者回復,說我文章的內容C++ Primer上都有。確實是這樣。作者寫作本連載的的目的,首先是參照C++Primer自己學習,然後融入自己的理解並與大家分享。 大師的書當然好,但是具體到每個人不一定一下子都能夠理解。通過作者的文章,大家可以在學習,理解的過程中哪怕

C++11特性(75)-隨機數庫(Random Number Library)

從前的隨機數 C++11之前,無論是C,還是C++都使用相同方式的來生成隨機數,程式碼大致如下: 由於rand()產生的是偽隨機數,所以需要為rand函式提供種子。種子不同產生的隨機數序列也不同。通常的做法是呼叫srand(time(0)),由於time返回的是系統時間,每秒都會不