最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺析C++可變參數(shù)模板的展開方式

 更新時(shí)間:2022年04月06日 14:15:24   作者:AlbertS  
可變參數(shù)模板(variadic templates)是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類型的參數(shù),這篇文章主要介紹了C++可變參數(shù)模板的展開方式,需要的朋友可以參考下

前言

可變參數(shù)模板(variadic templates)是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化,能表示0到任意個(gè)數(shù)、任意類型的參數(shù)。相比C++98/03這些類模版和函數(shù)模版中只能含固定數(shù)量模版參數(shù)的“老古董”,可變模版參數(shù)無(wú)疑是一個(gè)巨大的進(jìn)步。

如果是剛接觸可變參數(shù)模板可能會(huì)覺得比較抽象,使用起來(lái)會(huì)不太順手,使用可變參數(shù)模板時(shí)通常離不開模板參數(shù)的展開,所以本文來(lái)列舉一些常用的模板展開方式,幫助我們來(lái)對(duì)可變參數(shù)模板有一個(gè)初步的了解。

可變參數(shù)模板的定義

可變參數(shù)模板和普通模板的定義類似,在寫法上需要在 typenameclass 后面帶上省略號(hào)...,以下為一個(gè)常見的可變參數(shù)函數(shù)模板:

template <class... T>
void func(T... args)
{
    //...
}

上面這個(gè)函數(shù)模板的參數(shù) args 前面有省略號(hào),所以它就是一個(gè)被稱為模板參數(shù)包(template parameter pack)的可變模版參數(shù),它里面包含了0到N個(gè)模版參數(shù),而我們是無(wú)法直接獲取 args 中的每個(gè)參數(shù)的,只能通過(guò)展開參數(shù)包的方式來(lái)獲取參數(shù)包中的每個(gè)參數(shù),這也是本文要重點(diǎn)總結(jié)的內(nèi)容。

參數(shù)包的展開

參數(shù)包展開的方式隨著c++語(yǔ)言的發(fā)展也在與時(shí)俱進(jìn),我們以實(shí)現(xiàn)一個(gè)可變參格式化打印函數(shù)為例,列舉一些常用的方式:

遞歸函數(shù)方式展開

#include <iostream>
void FormatPrint()
{
    std::cout << std::endl;
}
template <class T, class ...Args>
void FormatPrint(T first, Args... args)
{
   std::cout << "[" << first << "]";
   FormatPrint(args...);
}
int main(void)
{
   FormatPrint(1, 2, 3, 4);
   FormatPrint("good", 2, "hello", 4, 110);
   return 0;
}

這種遞歸展開的方式與遞歸函數(shù)的定義是一樣的,需要遞歸出口和不斷調(diào)用自身,仔細(xì)看看這個(gè)函數(shù)模板是不是都滿足啦?遞歸出口就是這個(gè)無(wú)模板參數(shù)的 FormatPrint,并且在有參模板中一直在調(diào)用自身,遞歸調(diào)用的過(guò)程時(shí)這樣的 FormatPrint(4,3,2,1) -> FormatPrint(3,2,1) -> FormatPrint(2,1) -> FormatPrint(1) -> FormatPrint(),輸出內(nèi)容如下:

>albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++11
albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out
[1][2][3][4]
[good][2][hello][4][110]

逗號(hào)表達(dá)式展開

#include <iostream>
template <class ...Args>
void FormatPrint(Args... args)
{
   (void)std::initializer_list<int>{ (std::cout << "[" << args << "]", 0)... };
   std::cout << std::endl;
}

int main(void)
{
   FormatPrint(1, 2, 3, 4);
   FormatPrint("good", 2, "hello", 4, 110);
   return 0;
}

這種方式用到了C++11的新特性初始化列表(Initializer lists)以及很傳統(tǒng)的逗號(hào)表達(dá)式,我們知道逗號(hào)表達(dá)式的優(yōu)先級(jí)最低,(a, b) 這個(gè)表達(dá)式的值就是 b,那么上述代碼中(std::cout << "[" << args << "]", 0)這個(gè)表達(dá)式的值就是0,初始化列表保證其中的內(nèi)容從左往右執(zhí)行,args參數(shù)包會(huì)被逐步展開,表達(dá)式前的(void)是為了防止變量未使用的警告,運(yùn)行過(guò)后我們就得到了一個(gè)N個(gè)元素為0的初始化列表,內(nèi)容也被格式化輸出了:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++11
albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out
[1][2][3][4]
[good][2][hello][4][110]

說(shuō)到這順便提一下,可以使用sizeof...(args)得到參數(shù)包中參數(shù)個(gè)數(shù)。

enable_if方式展開

#include <iostream>
#include <tuple>
#include <type_traits>
template<std::size_t k = 0, typename tup>
typename std::enable_if<k == std::tuple_size<tup>::value>::type FormatTuple(const tup& t)
{
    std::cout << std::endl;
}
template<std::size_t k = 0, typename tup>
typename std::enable_if<k < std::tuple_size<tup>::value>::type FormatTuple(const tup& t){
    std::cout << "[" << std::get<k>(t) << "]";
    FormatTuple<k + 1>(t);
}
template<typename... Args>
void FormatPrint(Args... args)
{
    FormatTuple(std::make_tuple(args...));
}
int main(void)
{
   FormatPrint(1, 2, 3, 4);
   FormatPrint("good", 2, "hello", 4, 110);
   return 0;
}

C++11的enable_if常用于構(gòu)建需要根據(jù)不同的類型的條件實(shí)例化不同模板的時(shí)候。顧名思義,當(dāng)滿足條件時(shí)類型有效。可作為選擇類型的小工具,其廣泛的應(yīng)用在 C++ 的模板元編程(meta programming)之中,利用的就是SFINAE原則,英文全稱為Substitution failure is not an error,意思就是匹配失敗不是錯(cuò)誤,假如有一個(gè)特化會(huì)導(dǎo)致編譯時(shí)錯(cuò)誤,只要還有別的選擇,那么就無(wú)視這個(gè)特化錯(cuò)誤而去選擇另外的實(shí)現(xiàn),這里的特化概念不再展開,感興趣可以自行了解,后續(xù)可以單獨(dú)總結(jié)一下。

在上面的代碼實(shí)現(xiàn)中,基本思路是先將可變模版參數(shù)轉(zhuǎn)換為std::tuple,然后通過(guò)遞增參數(shù)的索引來(lái)選擇恰當(dāng)?shù)?code>FormatTuple函數(shù),當(dāng)參數(shù)的索引小于tuple元素個(gè)數(shù)時(shí),會(huì)不斷取出當(dāng)前索引位置的參數(shù)并輸出,當(dāng)參數(shù)索引等于總的參數(shù)個(gè)數(shù)時(shí)調(diào)用另一個(gè)模板重載函數(shù)終止遞歸,編譯運(yùn)行輸入以下內(nèi)容:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++11
albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out
[1][2][3][4]
[good][2][hello][4][110]

折疊表達(dá)式展開(c++17)

#include <iostream>
template<typename... Args>
void FormatPrint(Args... args)
{
    (std::cout << ... << args) << std::endl;
}
int main(void)
{
   FormatPrint(1, 2, 3, 4);
   FormatPrint("good", 2, "hello", 4, 110);
   return 0;
}

折疊表達(dá)式(Fold Expressions)是C++17新引進(jìn)的語(yǔ)法特性,使用折疊表達(dá)式可以簡(jiǎn)化對(duì)C++11中引入的參數(shù)包的處理,可以在某些情況下避免使用遞歸,更加方便的展開參數(shù),如上述代碼中展示的這樣可以方便的展開參數(shù)包,不過(guò)輸出的內(nèi)容和之前的有些不一樣:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++17
albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out
1234
good2hello4110

對(duì)比結(jié)果發(fā)現(xiàn)缺少了格式化的信息,需要以輔助函數(shù)的方式來(lái)格式化:

#include <iostream>
template<typename T>
string format(T t) {
    std::stringstream ss;
    ss << "[" << t << "]";
    return ss.str();
}
template<typename... Args>
void FormatPrint(Args... args)
{
    (std::cout << ... << format(args)) << std::endl;
}
int main(void)
{
   FormatPrint(1, 2, 3, 4);
   FormatPrint("good", 2, "hello", 4, 110);
   return 0;
}

這次格式化內(nèi)容就被加進(jìn)來(lái)了:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++17
albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out
[1][2][3][4]
[good][2][hello][4][110]

這樣好像還是有點(diǎn)麻煩,我們可以把折疊表達(dá)式和逗號(hào)表達(dá)式組合使用,這樣得到的代碼就簡(jiǎn)單多啦,也能完成格式化輸出的任務(wù):

#include <iostream>
template<typename... Args>
void FormatPrint(Args... args)
{
    (std::cout << ... << (std::cout << "[" << args, "]")) << std::endl;
}
int main(void)
{
   FormatPrint(1, 2, 3, 4);
   FormatPrint("good", 2, "hello", 4, 110);
   return 0;
}

總結(jié)

Variadic templates 是C++11新增的強(qiáng)大的特性之一,它對(duì)模板參數(shù)進(jìn)行了高度泛化Initializer lists 是C++11新加的特性,可以作為函數(shù)參數(shù)和返回值,長(zhǎng)度不受限制比較方便Fold Expressions 是C++17新引進(jìn)的語(yǔ)法特性,可以方便的展開可變參數(shù)模板的參數(shù)包可變參數(shù)模板的參數(shù)包在C++11的環(huán)境下,可以利用遞歸、逗號(hào)表達(dá)式、enable_if等方式進(jìn)行展開

==>> 反爬鏈接,請(qǐng)勿點(diǎn)擊,原地爆炸,概不負(fù)責(zé)!<<==

到此這篇關(guān)于C++可變參數(shù)模板的展開方式的文章就介紹到這了,更多相關(guān)C++模板展開方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言如何輸出中文

    C語(yǔ)言如何輸出中文

    這篇文章主要介紹了C語(yǔ)言如何輸出中文問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • C++簡(jiǎn)明圖解分析淺拷貝與深拷貝

    C++簡(jiǎn)明圖解分析淺拷貝與深拷貝

    在c++中,深拷貝和淺拷貝也算是一個(gè)難點(diǎn),特別是對(duì)于初學(xué)者來(lái)說(shuō),往往在不知道兩者區(qū)別的情況下而錯(cuò)誤的使用了淺拷貝,從而導(dǎo)致了野指針之類的問(wèn)題,但是又因?yàn)槿鄙倮斫馑院茈y定位到問(wèn)題所在
    2022-06-06
  • C語(yǔ)言實(shí)現(xiàn)古代時(shí)辰計(jì)時(shí)與現(xiàn)代時(shí)間換算

    C語(yǔ)言實(shí)現(xiàn)古代時(shí)辰計(jì)時(shí)與現(xiàn)代時(shí)間換算

    這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)古代時(shí)辰計(jì)時(shí)與現(xiàn)代時(shí)間換算,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2023-03-03
  • C語(yǔ)言結(jié)構(gòu)體使用之鏈表

    C語(yǔ)言結(jié)構(gòu)體使用之鏈表

    這篇文章主要介紹了C語(yǔ)言結(jié)構(gòu)體使用之鏈表,下面文章主要圍繞結(jié)構(gòu)體的概念和用法、結(jié)構(gòu)體數(shù)組和結(jié)構(gòu)體指針、包含結(jié)構(gòu)體的結(jié)構(gòu)體、結(jié)構(gòu)體搭建鏈表方法、結(jié)構(gòu)體及鏈表在產(chǎn)品應(yīng)用場(chǎng)景等多個(gè)主題展開鏈表的相關(guān)資料,需要的小伙伴可以參考一下
    2022-03-03
  • C++實(shí)現(xiàn)多源最短路徑之Floyd算法示例

    C++實(shí)現(xiàn)多源最短路徑之Floyd算法示例

    這篇文章主要介紹了C++實(shí)現(xiàn)多源最短路徑之Floyd算法,結(jié)合實(shí)例形式分析了多源最短路徑之Floyd算法的原理、實(shí)現(xiàn)方法及核心代碼,需要的朋友可以參考下
    2017-08-08
  • 用C++實(shí)現(xiàn)推箱子

    用C++實(shí)現(xiàn)推箱子

    這篇文章主要為大家詳細(xì)介紹了用C++實(shí)現(xiàn)推箱子,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • c++作用域運(yùn)算符用法(全局變量和局部變量)

    c++作用域運(yùn)算符用法(全局變量和局部變量)

    這篇文章主要介紹了c++作用域運(yùn)算符用法,需要的朋友可以參考下
    2014-04-04
  • C/C++編程判斷String字符串是否包含某個(gè)字符串實(shí)現(xiàn)示例

    C/C++編程判斷String字符串是否包含某個(gè)字符串實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了C++編程中判斷String字符串是否包含某個(gè)字符串的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • C++用boost.signal實(shí)現(xiàn)多播委托

    C++用boost.signal實(shí)現(xiàn)多播委托

    這篇文章介紹了C++用boost.signal實(shí)現(xiàn)多播委托的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • C++面試題之?dāng)?shù)a、b的值互換(不使用中間變量)

    C++面試題之?dāng)?shù)a、b的值互換(不使用中間變量)

    這篇文章主要介紹了不使用中間變量,C++實(shí)現(xiàn)數(shù)a、b的值互相轉(zhuǎn)換操作,感興趣的小伙伴們可以參考一下
    2016-07-07

最新評(píng)論

陆河县| 桂东县| 白河县| 资兴市| 庆云县| 盐边县| 顺平县| 姜堰市| 龙海市| 烟台市| 广德县| 宁津县| 马尔康县| 菏泽市| 嘉义县| 方山县| 巴彦淖尔市| 四川省| 丽水市| 建昌县| 乌鲁木齐市| 张家口市| 航空| 工布江达县| 新野县| 乌拉特后旗| 德兴市| 稷山县| 安岳县| 介休市| 大姚县| 美姑县| 常熟市| 彰化县| 宜阳县| 晋州市| 潼南县| 滦平县| 大余县| 平山县| 海阳市|