省略符號及可變參數範本
本文說明如何使用省略號 ( ...
) 搭配 C++ 變數範本。 省略號在 C 和 C++ 中有許多用途。 這些包含函式的變數引數清單。 來自 C 執行時間程式庫的函 printf()
式是其中一個最知名的範例。
variadic 範本 是支援任意數目引數的類別或函式範本。 此機制特別適用于 C++ 程式庫開發人員:您可以將它套用至類別範本和函式範本,進而提供廣泛的型別安全和非簡單功能和彈性。
語法
variadic 範本會以兩種方式使用省略號。 在參數名稱的左邊,它會表示 參數套件 ,並在參數名稱的右邊,將參數套件展開為個別的名稱。
以下是 variadic 類別範本 定義語法的基本範例 :
template<typename... Arguments> class classname;
針對參數套件和擴充,您可以根據您的喜好設定,在省略號周圍新增空白字元,如下列範例所示:
template<typename ...Arguments> class classname;
或此範例:
template<typename ... Arguments> class classname;
本文使用第一個範例中顯示的慣例(省略號附加至 typename
)。
在上述範例中, Arguments
是參數套件。 類別 classname
可以接受可變數目的引數,如下列範例所示:
template<typename... Arguments> class vtclass;
vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
vtclass<long, std::vector<int>, std::string> vtinstance4;
藉由使用 variadic 類別範本定義,您也可以至少需要一個參數:
template <typename First, typename... Rest> class classname;
以下是 variadic 函式範本 語法的基本範例 :
template <typename... Arguments> returntype functionname(Arguments... args);
然後,參數 Arguments
套件會展開以供使用,如下一節所示。
其他形式的 variadic 函式範本語法是可行的,包括但不限於下列範例:
template <typename... Arguments> returntype functionname(Arguments&... args);
template <typename... Arguments> returntype functionname(Arguments&&... args);
template <typename... Arguments> returntype functionname(Arguments*... args);
也允許像 這樣的 const
規範:
template <typename... Arguments> returntype functionname(const Arguments&... args);
如同 variadic 範本類別定義,您可以讓至少需要一個參數的函式:
template <typename First, typename... Rest> returntype functionname(const First& first, const Rest&... args);
Variadic 範本會使用 sizeof...()
運算子(與較舊的 sizeof()
運算子無關):
template<typename... Arguments>
void tfunc(const Arguments&... args)
{
constexpr auto numargs{ sizeof...(Arguments) };
X xobj[numargs]; // array of some previously defined type X
helper_func(xobj, args...);
}
進一步了解省略符號位置
本文先前說明以這個形式定義參數套件和展開的省略號位置:「在參數名稱左邊,它會表示參數套件,並在參數名稱的右邊,將參數套件展開為個別名稱」。 雖然在技術上是真的,但在翻譯至程式碼時可能會造成混淆。 考量:
在 template-parameter-list 中,
template <parameter-list>
typename...
引進範本參數套件。在 parameter-declaration-clause 中,
func(parameter-list)
「最上層」省略號引進函式參數套件,省略號定位很重要:// v1 is NOT a function parameter pack: template <typename... Types> void func1(std::vector<Types...> v1); // v2 IS a function parameter pack: template <typename... Types> void func2(std::vector<Types>... v2);
若省略符號在參數名稱之後顯示,您有參數封裝展開。
範例
說明 variadic 函式範本機制的好方法是在重寫 的一些功能 printf
時使用它:
#include <iostream>
using namespace std;
void print() {
cout << endl;
}
template <typename T> void print(const T& t) {
cout << t << endl;
}
template <typename First, typename... Rest> void print(const First& first, const Rest&... rest) {
cout << first << ", ";
print(rest...); // recursive call using pack expansion syntax
}
int main()
{
print(); // calls first overload, outputting only a newline
print(1); // calls second overload
// these call the third overload, the variadic template,
// which uses recursion as needed.
print(10, 20);
print(100, 200, 300);
print("first", 2, "third", 3.14159);
}
輸出
1
10, 20
100, 200, 300
first, 2, third, 3.14159
注意
大部分納入 variadic 函式範本的實作都會使用某種形式的遞迴,但與傳統遞迴稍有不同。 傳統的遞迴牽涉到使用相同簽章來呼叫本身的函式。 (可能會多載或範本化,但每次都會選擇相同的簽章。Variadic 遞迴牽涉到使用不同(幾乎一律遞減)引數數目來呼叫 variadic 函式範本,藉此每次戳出不同的簽章。 仍然需要「基底案例」,但遞迴的性質不同。
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應