C++模板(第二版)筆記之第四章:變參模板-創(chuàng)新互聯(lián)

文章目錄
    • 一、變參模板
      • 1.變參模板e(cuò)g
      • 2.變參和非變參模板的重載
      • 3.sizeof... 運(yùn)算符
  • 二、折疊表達(dá)式
  • 三、變參模板的使用
  • 四、變參類模板和變參表達(dá)式
    • 1.變參表達(dá)式

創(chuàng)新互聯(lián)建站堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:做網(wǎng)站、成都網(wǎng)站設(shè)計(jì)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的杭州網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!一、變參模板 1.變參模板e(cuò)g

可以將模板參數(shù)定義成能夠接受任意多個(gè)模板參數(shù)的情況。 這一類模板被稱為變參模板(variadic template)。

  • eg:可以通過調(diào)用下面代碼中的 print()函數(shù)來打印一組數(shù)量和類型都不確定的參數(shù):
#include//為了結(jié)束遞歸, 重載了不接受參數(shù)的非模板函數(shù) print(), 它會(huì)在參數(shù)包為空的時(shí)候被調(diào)用。
void print ()
{}

//這些被稱為 args的剩余參數(shù), 是一個(gè)函數(shù)參數(shù)包(function parameter pack) :
templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< '\n' ; //print first argument
    print(args…); // call print() for remaining arguments
}


int main()
{std::string s("world");
    print (7.5, "hello", s);
}
  • 測試:
7.5
hello
World

解釋:

  • 因?yàn)檫@個(gè)調(diào)用首先會(huì)被擴(kuò)展成:

print(7.5, “hello”, s);
其中:
firstArg 的值是 7.5, 其類型 T 是 double。
args 是一個(gè)可變模板參數(shù), 它包含類型是 char const*的“hello” 和類型是 std::string 的“world”

  • 在打印了 firstArg 對(duì)應(yīng)的 7.5 之后, 繼續(xù)調(diào)用 print()打印剩余的參數(shù), 這時(shí) print()被擴(kuò)展為:

print(“hello”, s);
其中:
firstArg 的值是“hello” , 其類型 T 是 char const *。
args 是一個(gè)可變模板參數(shù), 它包含的參數(shù)類型是 std::string。

  • 在打印了 firstArg 對(duì)應(yīng)的“hello” 之后, 繼續(xù)調(diào)用 print()打印剩余的參數(shù), 這時(shí) print()被擴(kuò)展為:
    print(s);

其中:
firstArg 的值是“world” , 其類型 T 是 std::string。
args 是一個(gè)空的可變模板參數(shù), 它沒有任何值

  • 這樣在打印了 firstArg 對(duì)應(yīng)的“ world” 之后, 就會(huì)調(diào)用被重載的不接受參數(shù)的非模板函數(shù)print(), 從而結(jié)束了遞歸。
2.變參和非變參模板的重載
  • eg:當(dāng)兩個(gè)函數(shù)模板的區(qū)別只在于尾部的參數(shù)包的時(shí)候, 會(huì)優(yōu)先選擇沒有尾部參數(shù)包的那一個(gè)函數(shù)模板。
#include//為了結(jié)束遞歸, 重載了不接受參數(shù)的非模板函數(shù) print(), 它會(huì)在參數(shù)包為空的時(shí)候被調(diào)用。
templatevoid print (T arg)
{std::cout<< arg<< '\n' ; //print passed argument
}

//這些被稱為 args的剩余參數(shù), 是一個(gè)函數(shù)參數(shù)包(function parameter pack) :
templatevoid print (T firstArg, Types... args)
{std::cout<< firstArg<< '\n' ; //print first argument
    print(args...); // call print() for remaining arguments
}
  • 另外:
#includetemplatevoid print(T arg)
{(std::cout<< arg)<< '\n';
}
int main()
{std::cout<< "Hello World";
    print();
    return 0;
}
  • 測試:
/home/insights/insights.cpp:10:5: error: no matching function for call to 'print'
    print();
    ^~~~~
/home/insights/insights.cpp:3:6: note: candidate function template not viable: requires single argument 'arg', but no arguments were provided
void print(T arg)
     ^
1 error generated.
Error while processing /home/insights/insights.cpp.
3.sizeof… 運(yùn)算符

C++11 為變參模板引入了一種新的 sizeof 運(yùn)算符: sizeof…。 它會(huì)被擴(kuò)展成參數(shù)包中所包含的參數(shù)數(shù)目。

  • 運(yùn)算符 sizeof…既可以用于模板參數(shù)包, 也可以用于函數(shù)參數(shù)包。
templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< ’ \n’ ; //print first argument
	std::cout<< sizeof…(Types)<< ’ \n’ ; //print number of remaining
	types
	std::cout<< sizeof…(args)<< ’ \n’ ; //print number of remainingargs
…
}
  • 錯(cuò)誤做法:這樣可能會(huì)讓你覺得, 可以不使用為了結(jié)束遞歸而重載的不接受參數(shù)的非模板函數(shù) print(),只要在沒有參數(shù)的時(shí)候不去調(diào)用任何函數(shù)就可以了:
templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< ’ \n’ ;
	if (sizeof…(args) >0) {//error if sizeof…(args)==0
		print(args…); // and no print() for no arguments declared
	}
}

解釋:

  • 但是這一方式是錯(cuò)誤的, 因?yàn)橥ǔ:瘮?shù)模板中 if 語句的兩個(gè)分支都會(huì)被實(shí)例化。

  • 因此如果在只有一個(gè)參數(shù)的時(shí)候調(diào)用 print()函數(shù)模板, 雖然 args…為空, if 語句中的 print(args…)也依然會(huì)被實(shí)例化, 但此時(shí)沒有定義不接受參數(shù)的 print()函數(shù),因此會(huì)報(bào)錯(cuò)

  • 其他方法:如果使用 constexp if, 就可以在函數(shù)內(nèi)部決定是否要繼續(xù)遞歸下去, 而不用再單獨(dú)定義一個(gè)函數(shù)來終結(jié)遞歸:

templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< ’ \n’ ;
	if constexpr(sizeof…(args) >0) {print(args…); //code only available if sizeof…(args)>0 (sinceC++17)
	}
}

解釋:

  • 這里如果只給 print()傳遞一個(gè)參數(shù), 那么 args…就是一個(gè)空的參數(shù)包, 此時(shí) sizeof…(args)等于
    0。
  • 這樣 if 語句里面的語句就會(huì)被丟棄掉, 也就是說這部分代碼不會(huì)被實(shí)例化。 因此也就不
    再需要一個(gè)單獨(dú)的函數(shù)來終結(jié)遞歸
二、折疊表達(dá)式

從 C++17 開始, 提供了一種可以用來計(jì)算參數(shù)包(可以有初始值) 中所有參數(shù)運(yùn)算結(jié)果的二元運(yùn)算符。

  • 幾乎所有的二元運(yùn)算符都可以用于折疊表達(dá)式
  • eg:下面的函數(shù)會(huì)返回 s 中所有參數(shù)的和。如果參數(shù)包是空的, 這個(gè)表達(dá)式將是不合規(guī)范的。
templateauto foldSum (T… s) {return (… + s); // ((s1 + s2) + s3) …
}

更好的方法

templateauto sum(T ...t)
{return (0+...+t);
}
  • 可能的折疊表達(dá)式:
    在這里插入圖片描述

  • eg:使用折疊表達(dá)式和運(yùn)算符->*遍歷一條二叉樹的路徑:

// define binary tree structure and traverse helpers:
struct Node {int value;
	Node* left;
	Node* right;
	Node(int i=0) : value(i), left(nullptr), right(nullptr) {}
};

auto left = &Node::left;
auto right = &Node::right;
// traverse tree, using fold expression:
templateNode* traverse (T np, TP… paths) 
{//折疊表達(dá)式從 np 開始遍歷了 paths 中所有可變成員。
	return (np ->* … ->* paths); // np ->* paths1 ->* paths2 …
}

int main()
{// init binary tree structure:
	Node* root = new Node{0};
	root->left = new Node{1};
	root->left->right = new Node{2}; 
	//traverse binary tree:
	Node* node = traverse(root, left, right);
}
  • eg:在參數(shù)包各元素之間并不會(huì)打印空格。它可以在所有要打印的參數(shù)后面追加一個(gè)空格:
templateclass AddSpace
{private:
	T const& ref; // refer to argument passed in constructor
public:
	AddSpace(T const& r): ref(r) {}

friend std::ostream& operator<< (std::ostream& os, AddSpaces) 
{return os<< s.ref<<’ ’ ; // output passed argument and a space
}
};

templatevoid print (Args… args) {( 
	std::cout<< …<< AddSpace(args) )<< ’ \n’ ;
}

//更好的方法
templatevoid print(T0 const &t0, T const &...t) {std::cout<< t0;
    ((std::cout<< ' '<< t), ...);
    std::cout<< std::endl;
}
三、變參模板的使用

一個(gè)重要的作用是轉(zhuǎn)發(fā)任意類型和數(shù)量的參數(shù)。

通常是使用移動(dòng)語義對(duì)參數(shù)進(jìn)行完美轉(zhuǎn)發(fā)(perfectly forwarded)

注意, 之前關(guān)于常規(guī)模板參數(shù)的規(guī)則同樣適用于變參模板參數(shù)。

  • 比如, 如果參數(shù)是按值傳遞的, 那么其參數(shù)會(huì)被拷貝, 類型也會(huì)退化(decay) 。 如果是按引用傳遞的, 那么參數(shù)會(huì)是實(shí)參的引用, 并且類型不會(huì)退化:
// args are copies with decayed types:
templatevoid foo (Args… args);
// args are nondecayed references to passed objects:
templatevoid bar (Args const&… args);
四、變參類模板和變參表達(dá)式

參數(shù)包還可以出現(xiàn)在其它一些地方, 比如表達(dá)式, 類模板, using 聲明, 甚至是推斷指引中。

1.變參表達(dá)式
  • eg:先是將參數(shù)包中的所有的參數(shù)都翻倍, 然后將結(jié)果傳給 print():
templatevoid printDoubled (T const&… args)
{print (args + args…);
}

如果這樣調(diào)用它:
printDoubled(7.5, std::string("hello"), std::complex(4,2));

效果上和下面的調(diào)用相同(除了構(gòu)造函數(shù)方面的不同) :
print(7.5 + 7.5, std::string("hello") + std::string("hello"),
std::complex(4,2) + std::complex(4,2);
  • 如果只是想向每個(gè)參數(shù)加 1, 省略號(hào)…中的點(diǎn)不能緊跟在數(shù)值后面:
templatevoid addOne (T const&… args)
{print (args + 1…); // ERROR: 1… is a literal with too many decimal points
print (args + 1 …); // OK
print ((args + 1)…); // OK
}
  • eg:折疊表達(dá)式的一種應(yīng)用:下面這個(gè)例子可以用來判斷所有參數(shù)包中參數(shù)的類型是否相同:
templateconstexpr bool isHomogeneous (T1, TN…)
{return (std::is_same::value && …); // since C++17
}

對(duì)于:
isHomogeneous(43, -1, "hello")
會(huì)被擴(kuò)展成:
std::is_same::value && std::is_same::value
結(jié)果自然是 false。 

而對(duì):isHomogeneous("hello", "", "world", "!")
結(jié)果則是 true, 因?yàn)樗械膮?shù)類型都被推斷為 char const *( 這里因?yàn)槭前粗祩鬟f, 所以
發(fā)生了類型退還, 否則類型將依次被推斷為: char const[6], char const[1], char const[6]和 char const[2]) 。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)站題目:C++模板(第二版)筆記之第四章:變參模板-創(chuàng)新互聯(lián)
網(wǎng)頁網(wǎng)址:http://bm7419.com/article28/ddhjcp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、靜態(tài)網(wǎng)站、關(guān)鍵詞優(yōu)化定制開發(fā)、網(wǎng)站策劃小程序開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名

網(wǎng)站設(shè)計(jì)公司知識(shí)