C++11新特性之變長參數模板詳解

C++11 變長參數模板

在C++11之前,無論是類模板 還是函數模板,都隻能按其指定的樣子,接受一組固定數量的模板參數;

這已經大大提升瞭代碼的復用!

在C++11之後,加入瞭新的表示方 法,允許任意個數、任意類別的模板參數,同時也不需要在定義時將參數的個數固定。更加像”黑魔法“瞭。

template<typename... Ts> class Magic;

模板類 Magic 的對象,能夠接受不受限制個數的 typename 作為模板的形式參數,例如下面的定義:

class Magic<int,
std::vector<int>,
std::map<std::string,
std::vector<int>>> darkMagic;

既然是任意形式,所以個數為 0 的模板參數也是可以的:class Magic<> nothing;。 如果不希望產生的模板參數個數為 0,可以手動的定義至少一個模板參數:

template<typename Require, typename... Args> class Magic;

變長函數參數包

除瞭在模板參數中能使用 … 表示不定長模板參數外,函數參數也使用同樣的表示法代表不定長參數。

傳統 C 中的 printf 函數,雖然也能達成不定個數 的形參的調用,但其並非類別安全。而 C++11 除瞭能定義類別安全的變長參數函數外,還可以使類似 printf 的函數能自然地處理非自帶類別的對象。除瞭在模板參數中能使用 … 表示不定長模板參數外, 函數參數也使用同樣的表示法代表不定長參數,這也就為我們簡單編寫變長參數函數提供瞭便捷的手段, 例如:

template<typename... Args> 
void printf(const std::string &str, Args... args);

其中,Args 與 args 分別代表模板與函數的變長參數集合, 稱之為參數包 (parameter pack)。參數包必須要和運算符”…”搭配使用。

如何解參數包

長參數模板中,變長參數包無法如同一般參數在類或函數中使用;這個很好理解!

因為在棧中,我們需要先知道函數有多少個參數,才可以入棧,但是我們不知道變長參數有多長,所以需要特殊手法!

sizeof()獲得函數參數個數

首先,我們可以使用 sizeof… 來計算參數的個數,:

template<typename... Ts>
void magic(Ts... args) 
{
    std::cout << sizeof...(args) << std::endl;
}

遞歸模板函數

遞歸去獲得所有參數,是非常容易想到的方法,這種方法不斷遞歸地向函數傳遞模板參數,進而達到遞歸遍歷所有模板參數的目的。

printf 會不斷地遞歸調用自身:函數參數包 args… 在調用時, 會被模板類別匹配分離為 T value和 Args… args。 直到 args… 變為空參數,則會與簡單的 printf(const char *s) 形成匹配,退出遞歸。

//遞歸模板函數
template<typename T0>
void printf1(T0 value)
{
    std::cout << value << std::endl;
}
template<typename T, typename... Ts>
void printf1(T value, Ts... args) 
{
    std::cout << value << std::endl;
    printf1(args...);
}
int RecursiveTemplateFunc() 
{
    printf1(1, 2, "123", 1.1);
    return 0;
}

變參模板展開

上面的遞歸很容易理解,但是比較繁瑣,那麼還有沒有什麼好方法呢?

在 C++17 中增加瞭變參模板展開的支持,於是你可以在一個函數中完 成 printf 的編寫:

//變參模板展開
template<typename T0, typename... T>
void printf2(T0 t0, T... t) 
{
    std::cout << t0 << std::endl;
    if constexpr (sizeof...(t) > 0) 
        printf2(t...);
}

結論

模板作為C++中的”黑魔法“般的武器,學起來比較難,但當掌握後,確實非常高級,變長參數模板對我們寫模板有很大的幫助!

本文的代碼地址: Modern_Cpp_Practice.

到此這篇關於C++11新特性之變長參數模板詳解的文章就介紹到這瞭,更多相關C++11 變長參數內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: