C++可變參數模板(variadic template)詳細介紹及代碼舉例

C++可變參數模板(variadic template)詳細介紹及代碼舉例html

C++11 語言核心的改進中,最爲關注的有 rvalue reference,lambda,variadic template。rvalue 規則稍微複雜,但一旦理解和記住了,應用上就沒有什麼困難。lambda 實際上是一個「很天然」的語言設施,除了語法稍顯詭異以外,習慣了就能立刻用上,並且是能普遍用上的好東西。variadic template 這個新特性不像前二者,它自己的語法規則並不複雜,可是應用的時候確比較費腦子,好在這個技術主要是用在庫的實現中,一個實現得好的庫,並不會讓咱們對實現的細節做任何的要求。可變參數模板(variadic template)特性自己是一個很天然的需求,它完善了 C++ 的模板設計手段。原來的模板參數可使類和函數的參數類型「任意化」,若是再加上「參數個數的任意化」,那麼在參數方面的設計手段就基本上齊備了,有了variadic template 顯然可讓設計出來的函數或是類有更大的複用性。由於有不少處理都是與「處理對象的個數」關係不大的,好比說打屏(printf),好比說比較大小(max,min),好比函數綁定子(bind,function要對應各類可能的函數就要能「任意」參數個數和類型)。若是不能對應任意個參數,那麼就總會有人沒法重用已有的實現,而不得再也不重複地寫一個本身須要的處理,而共通庫的實現者爲了儘量地讓本身寫的類(函數)能複用在更多的場景,也不得不重複地寫不少的代碼或是用詭異的技巧,宏之類的去實現有限個「任意參數」的對應。(像TR1中的 bind 等)。ios

1、C++可變參數模板(variadic template)基本語法c++

聲明一個帶有可變參數個數的模板的語法以下所示:程序員

template<typename Element> class tuple;web

tuple<int, string> a;  // use it like this安全

在模板參數 Element 左邊出現省略號 ... ,就是表示 Element 是一個模板參數包(template type parameter pack)。parameter pack(參數包)是新引入 C++ 中的概念,好比在這個例子中,Element 表示是一連串任意的參數打成的一個包。好比第2行中,Element 就是 int, string這個參數的合集。不只「類型」的模板參數(也就是typename定義的參數)能夠這樣作,非類型的模板參數也能夠這樣作。好比下面這個例子:ide

template<typename T, unsigned PrimaryDimesion, unsigned.. Dimesions>函數

class array { /**/ };this

array<double, 3, 3> rotation_matrix; //3x3 ratiation matrixspa

如今咱們知道parameter pack了,怎麼在程序中真正具體地去處理打包進來的「任意個數」的參數呢?我原來覺得,編譯器會提供一些像get_param<1>

(Element) 之類的內建的「參數抽取函數」給程序員使用結果不是!!看來個人思路仍是太「過程式了」。其實 C++11 用的是 unpack 和相似函數重載似的「模板特化」來抽取參數的。這是應用 variadic tempate 最「坑爹」的部分,由於它要求對「遞歸」和「人肉代碼展開」有必定的功力啊。仍是看例子吧:

template<typename... Elements> class tuple;

template<typename Head, typename... Tail>

class tuple<Head, Tail...> : private tuple<Tail...> {

   Head head;

public:

   /* implementation */

};

template<>

class tuple<> {

   /* zero-tuple implementation */

};

第1行聲明瞭一個能夠對應任意參數的tuple類,第2行到7行聲明瞭這個類的一個部分特化,注意,這就是抽取參數的典型方法了。

只說明一下針對 parameter pack 相對的另外一個概念,模板參數後面帶省略號 ... 就是一個解包(unpack),會把這個參數所表示的參數列表解開後去匹配新的模板,或是進行模板展開。

2、C++可變參數模板舉例

 新的標準庫裏,有不少個庫都直接依賴於 variadic template 這個語言特性,好比,tuple,bind,function。但他們比較複雜,也不夠「驚豔」。C++ 老爸的 C++11 的 FQA 和 Wikipedia 的例子都是「類型安全」的printf.

C++可變參數模板實例代碼1


void printf(const char *s)
{
    while (*s) {
        if (*s == '%') {
            if (*(s + 1) == '%') {
                ++s;
            }
            else {
                throw std::runtime_error("invalid format string: missing arguments");
            }
        }
        std::cout << *s++;
    }
}
template<typename T, typename... Args>
void printf(const char *s, T value, Args... args)
{
    while (*s) {
        if (*s == '%') {
            if (*(s + 1) == '%') {
                ++s;
            }
            else {
                std::cout << value;
                // call even when *s == 0 to detect extra arguments
                printf(s + 1, args...);
                return;
            }
        }
        std::cout << *s++;
    }
    throw std::logic_error("extra arguments provided to printf");
}


C++可變參數模板實例代碼2


/*
 *       g++ myPrintf.cpp -o myPrintf -std=c++0x -Wall
 *       來源:  169it
 */
#include <iostream>
#include <cstdlib>
#include <stdexcept>
void myPrintf(const char * s)
{
    while (*s)
    {
        if (*s == '%')
        {
            if (*(s + 1) == '%')
            {
                ++s;
            }
            else
            {
                throw std::runtime_error("invalid format string: missing arguments");
            }
        }
        std::cout << *s++;
    }
}
template<typename T, typename... Args>
void myPrintf(const char * s, T value, Args... args)
{
    while (*s)
    {
        if (*s == '%')
        {
            if (*(s + 1) == '%')
            {
                ++s;
            }
            else
            {
                std::cout << value;
                myPrintf(s + 1, args...); // 即使 *s == 0 的時候,也調用,以便用於檢測多餘的參數。
                return;
            }
        }
        std::cout << *s++;
    }
    throw std::logic_error("extra arguments provided to myPrintf");
}
int main ( )
{
    // 每個百分號,輸出一個參數
    myPrintf( "a%bcde%fghij%kl%mn\n", 12, "interesting", 8421, "very_interesing" );
    return EXIT_SUCCESS;
}

本文連接:C++可變參數模板(variadic template)詳細介紹及代碼舉例

相關文章
相關標籤/搜索