轉自:https://blog.csdn.net/m0_43383220/category_10485824.html
1 模板參數推導
1.1,C++17可對類模板的參數類型進行推導。
示例
1. 使用工廠方法 make_Type 構造對象(c++17 之前)
auto myPair = std::make_pair(42,"hello world"); //make_pair 是一個模板函數, //編譯器可根據輸入的模板參數類型推導出模板函數的參數類型, //不用寫成std::make_pair<int,std::string>; 2. c++17對類模板進行類型推導 std::pair my_pair{12,"hello world"}; //推導爲std::pair<int,std::string> auto ptr = new std::pair{13,"hello world"}; // 推導爲:std::pair<int,std::string> //lock guard std::mutex mtx; std::lock_guard lck(mtx); //推導爲:std::lock_guard<std::mutex> //array std::array arr{1,2,3}; //推導爲:std::array<int,3> //tuple std::tuple t1{1,2,3}; //ok std::tuple<int,int,int> t2{1,2,3}; // ok std::tuple<int> t3{1,2,3}; //推導錯誤,模板參數類型要麼寫全,要麼不寫。
推導說明
舉例 std::array 的推導規則。
template<typename _Tp, typename... _Up>
array(_Tp, _Up...)
-> array<enable_if_t<(is_same_v<_Tp, _Up> && ...), _Tp>,
1 + sizeof...(_Up)>;
//std::enable_if_t: std::enable_if<expression>::type
//std::is_same_v: std::is_same<T,U>::value
2. 摺疊表達式
C++ 17 對C++ 11中的可變參數模板進行了改進,使代碼更加簡潔易懂。
語法
- ( 形參包 op … )
- ( … op 形參包 )
- ( 形參包 op … op 初值 )
- ( 初值 op … op 形參包 )
形參包
含未展開的形參包且其頂層不含有優先級低於轉型的運算符的表達式
初值
不含未展開的形參包且其頂層不含有優先級低於轉型的運算符的表達式
注意3,4只有這兩種形式。即...必須位於中間,下面是不對的:
( op … op 初值 形參包 )
示例
遞歸函數求和
c++17 之前可變參數模板
//對加法的空包進行定義 即對遞歸的出口定義 auto Sum(){//c++14 auto返回值 return 0; } template<typename T1,typename... T> auto Sum(T1 s,T... ts){ return s + sum(ts); }
c++17 之後可變參數模板
auto Sum(){ //c++14 auto返回值 return 0; } //1.( 形參包 op ... ) template<typename ...Args>auto Sum1(Args ...args){ return (args + ...);//第一個參數展開+後面的在括號內遞歸展開。
//1+... => 1+(2+...)
//看紅色點點點被替換了。再變一步:1+(2+...) => 1+(2+())點點點用括號替換,
//以前的參數剩下是3,4,5,所以以前的...遞歸展開是 3+... 即 1+(2+(3+...)) } //2. ( ... op 形參包 ) template<typename ...Args> auto Sum2(Args ...args){ return (... + args);//後面的在括號內遞歸展開+第一個參數展開
//遞歸就是這樣變化
// () 即(... + 5) 變成
// (()) 即((...+4)+5) 變成
// ((())) 即(((...+3)+4)+5)
// (((()))) 即((((...+2)+3)+4)+5)
// ((((())))) 即(((((1)+2)+3)+4)+5)
} //3. ( 形參包 op ... op 初值 ) template<typename ...Args> auto Sum3(Args ...args){ return (args + ... + 0);//第一個args先拿出來,再後面的...要和0結合。
//1+(...+0)=>1+(2+(...+0)) => } //4. ( 初值 op ... op 形參包 ) template<typename ...Args> auto Sum4(Args ...args){ return (0 + ... + args);//(0+...)+5=》((0+...)+4)+5=> } auto res1 = Sum1(1,2,3,4,5); //展開爲:Sum1(1 + (2 + (3 + ( 4 + 5)))) auto res2 = Sum2(1,2,3,4,5); //展開爲:Sum2((((1 + 2) + 3) + 4) + 5); auto res3 = Sum3(1,2,3,4,5); //展開爲:Sum3(1 + (2 + (3 + (4 + (5 + 0))))) auto res4 = Sum4(1,2,3,4,5); //展開爲:Sum4(((((0 + 1) + 2) + 3) + 4) + 5)
將一元摺疊用於零長包展開時,僅允許下列運算符。
邏輯與
(&&),空包默認值爲true
;邏輯或
(||),空包默認值爲false
;逗號運算符
(,),空包默認值爲void()
。
輸出函數模板入參
template<typename ...Args> //定義了可變參數的類型 void PrintArgs(Args&&... args){ //定義函數,使用類型 (std::cout << ... << std::forward<Args>(args)) << std::endl; } PrintArgs("hello","world",1,3,4); //輸出參數無分隔:helloworld134 //2. template<typename ...Args> void PrintArgs2(Args&&... args){
//使用函數參數 Separator: auto Separator = [](const auto& v){//入參不一致,用auto進行推導 std::cout << v << ' '; //以空格分隔 }; (..., Separator(std::forward<Args>(args)));//給Separator函數一個個傳進去值!!! } PrintArgs2("hello","world",1,3,4);//輸出:hello world 1 3 4