【原】C++ 11 tuple & 可變參數模板

來源:互聯網
上載者:User

      C++ 11中引入的tuple是一個N元組。它相當於有N個成員的結構體,只不過這個結構體的成員都是匿名的。tuple中有兩個特殊的函數,一個是head(),用於擷取第一個成員的值,另一個是tail(),用於擷取剩下所有成員的值,tail()本身又是一個tuple。這樣,如果我們想取tuple中第二個成員的值,則可以先取tail()的值,再取tail()的head()的值。當然,這樣使用的話比較麻煩,所以C++ 11提供了get函數通過索引來擷取tuple中某個成員的值。另外,通過make_tuple可以很方便地構造一個tuple對象。有關tuple使用的例子可以參考下面的代碼。

1  tuple<int, char, string> tupInfo(10, 'A', "hello world");
2  int a = tupInfo.head();
3  int a2 = tupInfo.tail().head();
4  tuple<char, string> tupTail = tupInfo.tail();
5  int b = get<0>(tupInfo);
6  char c = get<1>(tupInfo);
7  string s = get<2>(tupInfo);
8  auto tupInfo2 = make_tuple(5, 'B', string("C++ 11"), 4.6);

      前面說過,tuple是一個N元組,而N的個數是沒有限制的,也就是說,tuple可以包含0個、1個、2個或更多的元素,每個元素的類型則通過模板參數指定。那麼,tuple是如何做到這些的呢?答案是可變參數模板。
      學習C++的人應當對printf函數都非常熟悉,printf的一個特點就是它的參數個數是可變的。而在C++ 11中,則允許模板的參數個數也是可變的。下面是一個模板參數可變的函數模板,用於擷取傳入的參數的個數。

1 template<typename... Args>
2 UINT GetParameterCount(Args... args)
3 {
4  return sizeof...(args);
5 }

      可以看到,可變參數模板使用typename再加...來表示模板參數包,使用Args再加...來表示函數參數包。上面代碼中的sizeof...專門用於擷取函數參數包中參數的個數,它的參數必須是一個函數參數包類型的對象。熟悉了可變參數模板的基本文法後,下面我們使用它來編寫一個Print函數,該函數的參數個數和類型都是可變的,它簡單地輸出傳入的各個參數的值,值之間用逗號進行分割,並在輸出最後一個參數的值後自動換行。

 1 template<typename T>
 2 void Print(T value)
 3 {
 4  cout << value << endl;
 5 }
 6 
 7 template<typename Head, typename... Rail>
 8 void Print(Head head, Rail... rail)
 9 {
10  cout << head << ",";
11  Print(rail...);
12 }
13 
14 int main(int argc, char *argv[])
15 {
16  Print(1);                  // 輸出:1
17  Print(1, "hello");         // 輸出:1,Hello
18  Print(1, "hello", 'H');    // 輸出:1,Hello,H
19  return 0;
20 }

       在上面的代碼中,我們先定義了一個只有一個模板參數的函數模板,它簡單地輸出傳入的參數的值。然後又定義了一個可變參數的函數模板,它輸出第一個參數的值,然後遞迴地調用自己。注意rail...這種寫法,它表示將函數參數包分割成一個一個的參數,並傳入Print中。這樣,函數參數包中的第一個參數傳遞給head,剩餘的參數又重新構成一個函數參數包傳遞給rail。當遞迴調用到函數參數包中只有一個參數時,則會調用只有一個模板參數的Print函數。
      理解了可變模板參數的使用原理後,我們再來編寫一個自己的Printf函數。

 1 void MyPrintf(const char *pszText)
 2 {
 3  assert(pszText != NULL);
 4 
 5  cout << pszText;
 6 }
 7 
 8 template<typename T, typename... Args>
 9 void MyPrintf(const char *pszText, T value, Args... args)
10 {
11  assert(pszText != NULL);
12 
13  while (*pszText)
14  {
15   if (*pszText == '%' && *++pszText != '%')
16   {
17    cout << value;
18    MyPrintf(++pszText, args...);
19    return;
20   }
21   cout << *pszText++;
22  }
23 }

      調用MyPrintf函數時的推理過程與Print的推理過程類似,這裡就不再贅述了。另外,如果想更深入地學習可變參數模板,還可以參閱tuple的原始碼,或者自己動手實現一個簡化版的tuple。

 

      介紹C++ 11新特性的文章列表:

          1、【原】C++ 11右值引用

          2、【原】C++ 11 Lambda運算式

          3、【原】C++ 11 auto & decltype
          4、【原】C++ 11完美轉寄

          5、【原】C++ 11文法甜點

          6、【原】C++ 11 tuple & 可變參數模板

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.