国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C++可變參數的函數與模板實例分析

2020-05-23 14:22:09
字體:
來源:轉載
供稿:網友

本文實例展示了C++可變參數的函數與模板的實現方法,有助于大家更好的理解可變參數的函數與模板的應用,具體內容如下:

首先,所謂可變參數指的是函數的參數個數可變,參數類型不定的函數。為了編寫能處理不同數量實參的函數,C++提供了兩種主要的方法:如果所有的實參類型相同,可以傳遞一個名為initializer_list的標準庫類型;如果實參的類型不同,我們可以編寫可變參數模板。另外,C++還有一種特殊的省略符形參,可以用它傳遞可變數量的實參,不過這種一般只用于與C函數交互的接口程序。

一、可變參數函數

1、initializer_list形參

如果函數的實參數量未知但是全部實參的類型都相同,我們可以使用initializer_list類型的形參(C++11新標準)。和vector一樣,initializer_list也是一種模板類型。下面看看initializer_list提供的一些操作:

#include<initializer_list> // 頭文件 initializer_list<T> lst;  // 默認初始化,T類型元素的空列表 initializer_list<T> lst{a,b,c...}; // 初始化為初始值列表的副本 lst2(lst)   // 拷貝或賦值不會拷貝列表中的元素;拷貝后, lst2 = lst  // 原始列表和副本共享元素 lst.size()  // 列表中的元素數量 lst.begin()  // 返回指向lst中首元素的指針 lst.end()   // 返回指向lst中尾元素下一位置的指針

下面給出一個例子,需要注意的是,含有initializer_list形參的函數也可以同時擁有其他形參。另外,如果想給initializer_list形參傳遞一個實參的序列,必須把序列放在一對花括號內:

string func(initializer_list<string> li) {   string str("");   for(auto beg=li.begin(); beg!=li.end(); ++beg)     str += *beg;   return str; }  int main() {   cout << func({"This"," ","is"," ","C++"}) << endl;   return 0; } 

2、省略符形參

函數可以用省略符形參”…“表示不定參數部分,省略符形參只能出現在形參列表的最后一個位置,它的形式如下:

void foo(parm_list, ...); // 典型例子 int printf(const char* format, ...) 

省略符形參應該僅僅用于C和C++通用的類型,因為大多數類類型的對象在傳遞給省略符形參時都無法正確拷貝。下面是<cstdarg>頭文件中的幾個宏定義:

#include<cstdarg> // C中是<stdarg.h>  // va_list是一種數據類型,args用于持有可變參數。 // 定義typedef char* va_list; va_list args;  // 調用va_start并傳入兩個參數:第一個參數為va_list類型的變量 // 第二個參數為"..."前最后一個參數名 // 將args初始化為指向第一個參數(可變參數列表) va_start(args, paramN);  // 檢索參數,va_arg的第一個參數是va_list變量,第二個參數指定返回值的類型 // 每一次調用va_arg會獲取當前的參數,并自動更新指向下一個可變參數。 va_arg(args,type);  // 釋放va_list變量 va_end(args);

下面給出一個例子:

int add_nums(int count,...) {   int result = 0;      va_list args;   va_start(args, count);   for(int i=0; i<count; ++i)     result += va_arg(args, int);   va_end(args);   return result; }  int main() {   cout << add_nums(4, 25, 25, 50, 50) << endl;   return 0; } 

編譯器是將參數壓入棧中進行傳遞的。傳遞實參的時候,編譯器會從實參列表中,按從右到左的順序將參數入棧,對于add_nums(4, 25, 25, 50, 50)的調用,則入棧的順序是 50, 50, 25, 25, 4 (注意沒有可變參數與不可變參數之分)。由于棧的地址是從高到低的,所以在知道了第一個參數地址和參數的類型之后,就可以獲取各個參數的地址。

二、可變參數模板

一個可變參數模板(variadic template)就是一個接受可變數目參數的模板函數或模板類。可變數目的參數被稱為參數包(parameter packet)。存在兩種參數包:模板參數包(表示零個或多個模板參數)和函數參數包(表示零個或多個函數參數)。

上述說到我們可以使用一個initializer_list來定義一個可接受可變數目實參的函數,但是所有實參必須具有相同的類型。當我們既不知道要處理的實參數目也不知道它們的類型時,我們就需要使用可變參數的函數模板了。我們用一個省略號來指出一個模板參數或函數參數表示一個包:在一個模板參數列表中,class...或typename...指出接下來的參數表示零個或多個類型的列表;一個類型名后面跟一個省略號表示零個或多個給定類型的非類型參數的列表。在函數參數列表中,如果一個參數的類型是一個模板參數包,則此參數也是一個函數參數包。

// Args是一個模板參數包;rest是一個函數參數包 template <typename T, typename...Args> void foo(const T &t, const Args&...rest); 

可變參數函數模板通常是遞歸的。第一步調用處理包中的第一個實參,然后用剩余的實參調用自身。為了終止遞歸,我們還需要定義一個非可變參數的函數模板:

// 用來終止遞歸并處理包中最后一個元素 template <typename T> void print(const T &t) {   cout << t; }  // 包中除了最后一個元素之外的其他元素都會調用這個版本的print template <typename T, typename...Args> void print(const T &t, const Args&...rest) {   cout << t << " ";   // 打印第一個實參   print(rest...);    // 遞歸調用,打印其他實參 }  // 測試 int main() {   print("string1", 2, 3.14f, "string2", 42);   cout << endl;   return 0; } 

非可變參數版本的print負責終止遞歸并打印初始調用中的最后一個實參。對于最后一次遞歸調用print(42),兩個print版本都是可行的。但是,非可變參數模板比可變參數模板更特例化,因此編譯器選擇非可變參數版本。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 陆良县| 镇宁| 孝义市| 嫩江县| 柞水县| 任丘市| 通辽市| 志丹县| 宝清县| 贞丰县| 五家渠市| 鄂托克前旗| 聊城市| 色达县| 肃南| 凤城市| 寿宁县| 新乐市| 岳普湖县| 日照市| 湘乡市| 宁城县| 桂平市| 潜山县| 博乐市| 长沙县| 北辰区| 苍山县| 襄樊市| 攀枝花市| 田东县| 宜章县| 新津县| 武宁县| 故城县| 呼玛县| 延长县| 甘孜| 旌德县| 磐安县| 鹤山市|