自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

可能學(xué)了假的編程?C++新標(biāo)準(zhǔn)難點(diǎn)解析之可變模板參數(shù)

開發(fā) 后端
C++的新特性--可變模版參數(shù)(variadic templates)是C++新增的最強(qiáng)大的特性之一,它對(duì)參數(shù)進(jìn)行了高度泛化,它能表示0到任意個(gè)數(shù)、任意類型的參數(shù)。相比C++98/03,類模版和函數(shù)模版中只能含固定數(shù)量的模版參數(shù),可變模版參數(shù)無(wú)疑是一個(gè)巨大的改進(jìn)。然而由于可變模版參數(shù)比較抽象,使用起來(lái)需要一定的技巧,所以它也是C++中最難理解和掌握的特性之一。

 前言

C++的新特性--可變模版參數(shù)(variadic templates)是C++新增的最強(qiáng)大的特性之一,它對(duì)參數(shù)進(jìn)行了高度泛化,它能表示0到任意個(gè)數(shù)、任意類型的參數(shù)。相比C++98/03,類模版和函數(shù)模版中只能含固定數(shù)量的模版參數(shù),可變模版參數(shù)無(wú)疑是一個(gè)巨大的改進(jìn)。然而由于可變模版參數(shù)比較抽象,使用起來(lái)需要一定的技巧,所以它也是C++中最難理解和掌握的特性之一。雖然掌握可變模版參數(shù)有一定難度,但是它卻是C++11中最有意思的一個(gè)特性,本文希望帶領(lǐng)讀者由淺入深地認(rèn)識(shí)和掌握這一特性,同時(shí)也會(huì)通過一些實(shí)例來(lái)展示可變參數(shù)模版的一些用法。

[[380966]]

變模版參數(shù)的展開

可變參數(shù)模板和普通模板的語(yǔ)義是一樣的,只是寫法上稍有區(qū)別,聲明可變參數(shù)模板時(shí)需要在typename或class后面帶上省略號(hào)“...”。比如我們常常這樣聲明一個(gè)可變模版參數(shù):template

  1. template <class... T> 
  2. void f(T... args); 

 省略號(hào)的作用:

1.聲明一個(gè)參數(shù)包T... args,這個(gè)參數(shù)包中可以包含0到任意個(gè)模板參數(shù); 2.在模板定義的右邊,可以將參數(shù)包展開成一個(gè)一個(gè)獨(dú)立的參數(shù)。

省略號(hào)的參數(shù)稱為“參數(shù)包”,它里面包含了0到N(N>=0)個(gè)模版參數(shù)。我們無(wú)法直接獲取參數(shù)包args中的每個(gè)參數(shù)的,只能通過展開參數(shù)包的方式來(lái)獲取參數(shù)包中的每個(gè)參數(shù),這是使用可變模版參數(shù)的一個(gè)主要特點(diǎn),也是最大的難點(diǎn),即如何展開可變模版參數(shù)。

可變模板參數(shù)分類:

1.可變模版參數(shù)函數(shù)

2.可變模版參數(shù)類

打印可變模版參數(shù)函數(shù)的參數(shù)個(gè)數(shù)

  1. #include <iostream> 
  2. #include <string> 
  3. using namespace std; 
  4. template <class ...Type> 
  5. void print(Type ...data)  
  6.     cout << sizeof...(data) << endl; 
  7. int main()  
  8.     print(); 
  9.     print(1); 
  10.     print(1, "ILoveyou"); 
  11.     print(1, 2, 3.4, "IMissyou"); 
  12.     return 0; 

 上面的例子中,print()沒有傳入?yún)?shù),所以參數(shù)包為空,輸出的size為0,后面兩次調(diào)用分別傳入兩個(gè)和三個(gè)參數(shù),故輸出的size分別為2和3。由于可變模版參數(shù)的類型和個(gè)數(shù)是不固定的,所以我們可以傳任意類型和個(gè)數(shù)的參數(shù)給函數(shù)print。這個(gè)例子只是簡(jiǎn)單的將可變模版參數(shù)的個(gè)數(shù)打印出來(lái),如果我們需要將參數(shù)包中的每個(gè)參數(shù)打印出來(lái)的話就需要通過一些方法了。

展開可變模版參數(shù)函數(shù)的方法一般有兩種:

1.通過遞歸函數(shù)來(lái)展開參數(shù)包。

2.逗號(hào)表達(dá)式來(lái)展開參數(shù)包。

遞歸方式展開參數(shù)包

通過遞歸函數(shù)展開參數(shù)包,需要提供一個(gè)參數(shù)包展開的函數(shù)和一個(gè)遞歸終止函數(shù),遞歸終止函數(shù)正是用來(lái)終止遞歸的,如下面的例子:

  1. #include <iostream> 
  2. using namespace std; 
  3. //遞歸終止函數(shù) 
  4. void print() 
  5.     cout << "遞歸終止函數(shù)" << endl; 
  6. //展開函數(shù) 
  7. template <class T,class ...Type> 
  8. void print(T data,Type...exData) 
  9.     cout << data << endl; 
  10.     print(exData...); 
  11. int main() 
  12.     print(1, 2, 3, 4); 
  13.     return 0; 

 上例會(huì)輸出每一個(gè)參數(shù),直到為空時(shí)輸出"遞歸終止函數(shù)"。展開參數(shù)包的函數(shù)有兩個(gè),一個(gè)是遞歸函數(shù),另外一個(gè)是遞歸終止函數(shù),參數(shù)包exData...在展開的過程中遞歸調(diào)用自己,每調(diào)用一次參數(shù)包中的參數(shù)就會(huì)少一個(gè),直到所有的參數(shù)都展開為止,當(dāng)沒有參數(shù)時(shí),則調(diào)用非模板函數(shù)print終止遞歸過程。當(dāng)然上述終止函數(shù)也可以寫成帶參數(shù)函數(shù)模板:

  1. template <class T> 
  2. void print(T data) 
  3.  cout<<data<endll    

 接下來(lái)用模板函數(shù)作為終止函數(shù)寫一個(gè)不限參求和函數(shù),具體實(shí)現(xiàn)代碼如下:

  1. #include <iostream> 
  2. using namespace std; 
  3. //遞歸終止函數(shù) 
  4. template <typename Type> 
  5. Type sum(Type t)  
  6.     return t; 
  7. //展開函數(shù) 
  8. template <class T,class ...Type> 
  9. sum(T a, Type ...b)  
  10.     return a + sum<T>(b...); 
  11. int main() 
  12.     cout << sum(1, 2, 3, 4) << endl; 
  13.     cout << sum(1, 2, 3) << endl; 
  14.     return 0; 

 sum在展開參數(shù)包的過程中將各個(gè)參數(shù)相加求和,參數(shù)的展開方式和前面的打印參數(shù)包的方式是一樣的。

逗號(hào)表達(dá)式展開參數(shù)包

遞歸函數(shù)展開參數(shù)包是一種標(biāo)準(zhǔn)做法,也比較好理解,但也有一個(gè)缺點(diǎn),就是必須要一個(gè)重載的遞歸終止函數(shù),即必須要有一個(gè)同名的終止函數(shù)來(lái)終止遞歸,這樣可能會(huì)感覺稍有不便。有沒有一種更簡(jiǎn)單的方式呢?其實(shí)還有一種方法可以不通過遞歸方式來(lái)展開參數(shù)包,這種方式需要借助逗號(hào)表達(dá)式和初始化列表。比如前面打印函數(shù)可以改成這樣:

  1. #include <iostream> 
  2. using namespace std; 
  3. //遞歸終止函數(shù) 
  4. template <class T> 
  5. void print(T data)  
  6.     cout << data << "\t"
  7. template <class ...Type> 
  8. void print(Type ...exData)  
  9.     int array[] = { (print(exData),0)... }; 
  10.  
  11. int main() 
  12.     print(1, 2, 3); 
  13.     cout << endl; 
  14.     print("張三", 1, 3); 
  15.     return 0; 

 這個(gè)數(shù)組的目的純粹是為了在數(shù)組構(gòu)造的過程展開參數(shù)包。我們可以把上面的例子再進(jìn)一步改進(jìn)一下,將函數(shù)作為參數(shù),就可以支持lambda表達(dá)式了,從而可以少寫一個(gè)遞歸終止函數(shù)了,具體代碼如下:

C++中新特性之:initializer_list詳解

C++11提供的新類型,定義在頭文件中。

  1. template< class T > 
  2. class initializer_list; 

 下面稍微介紹一下initializer_list

一個(gè)initializer_list當(dāng)出現(xiàn)在以下兩種情況的被自動(dòng)構(gòu)造:

  1. 當(dāng)初始化的時(shí)候使用的是大括號(hào)初始化,被自動(dòng)構(gòu)造。包括函數(shù)調(diào)用時(shí)和賦值
  2. 當(dāng)涉及到for(initializer: list),list被自動(dòng)構(gòu)造成initializer_list對(duì)象

也就是說initializer_list對(duì)象只能用大括號(hào){}初始化??截愐粋€(gè)initializer_list對(duì)象并不會(huì)拷貝里面的元素。其實(shí)只是引用而已。而且里面的元素全部都是const的。下面一個(gè)例子可以幫助我們更好地理解如何使用initializer_list:

  1. #include <iostream> 
  2. #include <vector> 
  3. #include <initializer_list> 
  4.  
  5. using namespace std; 
  6.  
  7. template <class T> 
  8. struct S  
  9.     vector<T> v; 
  10.     S(initializer_list<T> l) : v(l) { 
  11.         cout << "constructed with a " << l.size() << "-elements lists" << endl; 
  12.     } 
  13.     void append(std::initializer_list<T> l) { 
  14.         v.insert(v.end(), l.begin(), l.end()); 
  15.     } 
  16.  
  17.     pair<const T*, size_t> c_arr() const { 
  18.         return { &v[0], v.size() }; 
  19.     } 
  20. }; 
  21. template <typename T> 
  22. void templated_fn(T arg) { 
  23.     for (auto a : arg) 
  24.         cout << a << " "
  25.     cout << endl; 
  26.  
  27. int main()  
  28.     S<int> s = { 1, 2, 3, 4, 5 };                 
  29.     s.append({ 6, 7 , 8 });         
  30.     for (auto n : s.v) 
  31.         cout << ' ' << n; 
  32.     cout << endl; 
  33.     for (auto x : { -1, -2, 03 })   
  34.         cout << x << " "
  35.     cout << endl; 
  36.     auto al = { 10, 11, 12 };  
  37.     templated_fn<initializer_list<int> >({ 7, 8, 9 });  
  38.     templated_fn<vector<int>>({ 3, 5, 7 });        
  39.  
  40.     return 0; 

 可變模版參數(shù)類

std::tuple就是一個(gè)可變模板類

  1. template< class... Types > 
  2. class tuple; 

 這個(gè)可變參數(shù)模板類可以攜帶任意類型任意個(gè)數(shù)的模板參數(shù):

  1. tuple<int> tp1 = std::make_tuple(1); 
  2. tuple<intdouble> tp2 = std::make_tuple(1, 2.5); 
  3. tuple<intdouble, string> tp3 = std::make_tuple(1, 2.5, “”); 

 可變參數(shù)模板的模板參數(shù)個(gè)數(shù)可以為0個(gè),所以下面的定義也是也是合法的:

  1. tuple<> tp; 

可變參數(shù)模板類的參數(shù)包展開的方式和可變參數(shù)模板函數(shù)的展開方式不同,可變參數(shù)模板類的參數(shù)包展開需要通過模板特化和繼承方式去展開,展開方式比可變參數(shù)模板函數(shù)要復(fù)雜。

模版偏特化和遞歸方式來(lái)展開參數(shù)包

基本的可變參數(shù)模板類

  1. //前向聲明 
  2. template<typename... Args> 
  3. struct Sum
  4.  
  5. //基本定義 
  6. template<typename First, typename... Rest> 
  7. struct Sum<First, Rest...> 
  8.     enum { value = Sum<First>::value + Sum<Rest...>::value }; 
  9. }; 
  10.  
  11. //遞歸終止 
  12. template<typename Last
  13. struct Sum<Last
  14.     enum { value = sizeof (Last) }; 
  15. }; 
  16. int main() 
  17.     cout << Sum<intdouble, short>::value << endl; 
  18.     return 0; 

 繼承方式展開參數(shù)包

  1. //整型序列的定義 
  2. template<int...> 
  3. struct IndexSeq{}; 
  4.  
  5. //繼承方式,開始展開參數(shù)包 
  6. template<int N, int... Indexes> 
  7. struct MakeIndexes : MakeIndexes<N - 1, N - 1, Indexes...> {}; 
  8.  
  9. // 模板特化,終止展開參數(shù)包的條件 
  10. template<int... Indexes> 
  11. struct MakeIndexes<0, Indexes...> 
  12.     typedef IndexSeq<Indexes...> type; 
  13. }; 
  14.  
  15. int main() 
  16.     using T = MakeIndexes<3>::type; 
  17.     cout <<typeid(T).name() << endl; 
  18.     return 0; 

 可變參數(shù)模版消除重復(fù)代碼

C++11之前如果要寫一個(gè)泛化的工廠函數(shù),這個(gè)工廠函數(shù)能接受任意類型的入?yún)?,并且參?shù)個(gè)數(shù)要能滿足大部分的應(yīng)用需求的話,我們不得不定義很多重復(fù)的模版定義,比如下面的代碼:

  1. #include <iostream> 
  2. using namespace std; 
  3. template<typename T, typename...  Args> 
  4. T* Instance(Args... args) 
  5.     return new T(args...); 
  6. class A 
  7. public
  8.     A(int a) :a(a) {} 
  9.     A(int a, int b) :a(a) {} 
  10.     A(int a, int b,string c) :a(a) {} 
  11.     void print()  
  12.     { 
  13.         cout << a << endl; 
  14.     } 
  15.     int a; 
  16. }; 
  17. class B  
  18. public
  19.     B(int a, int b) :a(a), b(b) {} 
  20.     void print() 
  21.     { 
  22.         cout << a << endl; 
  23.         cout << b << endl; 
  24.     } 
  25.     int a; 
  26.     int b; 
  27. }; 
  28. int main() 
  29.     A* pa = Instance<A>(1); 
  30.     B* pb = Instance<B>(1, 2); 
  31.     pa->print(); 
  32.     pb->print(); 
  33.     pa = Instance<A>(100, 2); 
  34.     pa->print(); 
  35.     pa = Instance<A>(100, 2,"Loveyo"); 
  36.     pa->print(); 
  37.     return 0; 

 

 萬(wàn)能函數(shù)

  1. template <class T, class R, typename... Args> 
  2. class  MyDelegate 
  3. public
  4.     MyDelegate(T* t, R  (T::*f)(Args...) ):m_t(t),m_f(f) {} 
  5.     R operator()(Args... args) 
  6.     { 
  7.         return (m_t->*m_f)(args ...); 
  8.     } 
  9.     //R operator()(Args&&... args)  
  10.     //{ 
  11.             //return (m_t->*m_f)(std::forward<Args>(args) ...); 
  12.     //} 
  13.  
  14. private: 
  15.     T* m_t; 
  16.     R  (T::*m_f)(Args...); 
  17. };    
  18.  
  19. template <class T, class R, typename... Args> 
  20. MyDelegate<T, R, Args...> CreateDelegate(T* t, R (T::*f)(Args...)) 
  21.     return MyDelegate<T, R, Args...>(t, f); 
  22.  
  23. struct A 
  24.     void Fun(int i){cout<<i<<endl;} 
  25.     void Fun1(int i, double j){cout<<i+j<<endl;} 
  26. }; 
  27.  
  28. int main() 
  29.     A a; 
  30.     auto d = CreateDelegate(&a, &A::Fun); //創(chuàng)建委托 
  31.     d(1); //調(diào)用委托,將輸出1 
  32.     auto d1 = CreateDelegate(&a, &A::Fun1); //創(chuàng)建委托 
  33.     d1(1, 2.5); //調(diào)用委托,將輸出3.5 

 【編輯推薦】

 

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2012-09-18 13:26:39

CC++

2010-01-14 09:55:30

C++標(biāo)準(zhǔn)庫(kù)

2017-09-30 10:17:24

云計(jì)算PaaS容器云

2010-01-26 13:55:07

C++標(biāo)準(zhǔn)模板庫(kù)

2010-05-28 18:31:25

Nagios配置

2023-12-13 10:51:49

C++函數(shù)模板編程

2010-02-03 17:42:33

C++模板參數(shù)

2013-08-14 13:11:10

2011-07-10 15:26:54

C++

2022-09-22 10:22:36

C++編程語(yǔ)言代碼

2016-08-31 21:52:46

移動(dòng)云安全行業(yè)標(biāo)準(zhǔn)

2010-02-03 15:06:02

C++可變參數(shù)表

2010-09-03 15:09:08

DIV+CSS

2010-01-28 13:15:43

C++參數(shù)

2022-01-17 10:12:47

C++‘模板元編程

2011-05-13 17:25:34

C

2023-12-15 10:14:38

C++模板編程

2010-02-06 14:28:38

C++標(biāo)準(zhǔn)輸入輸出

2011-07-10 15:49:34

C++

2010-02-06 17:21:20

C++ CreateT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)