可変個テンプレート

まず、テンプレート宣言の型名(ここでは T)の前に pack 演算子を加えます。次に、関数パラメータの型名(ここでは args)の前にも pack 演算子を加えます。以下が基本的な記述法です。

template<typename ... T> void foo(T ... args);

連続したピリオド三文字が pack 演算子です。他の演算子と同じく、前後に空白文字を入れることができます。

ここで、関数へ渡される型名 T とパラメータ args には、内部に複数の型とパラメータが pack されています。これらは、使用する前に unpack 演算子を使って分解する必要があります。分解には、再帰呼び出しを使います。

void foo() {
}
template<typename T, typename ... Args>
void foo(const T & arg, Args ... args) {
    std::cout << arg << std::endl;
    foo(args...);
}

foo の再帰呼び出しに使用しているパラメータ名の直後に記述しているピリオド三文字が unpack 演算子です。この演算子をつけたパラメータを含んだ関数呼び出しは、pack されている複数の型を展開した結果の順列に合致したパラメータ群を持つオーバーロードされた関数を選択します。

前の例では、foo(1, "2"); のように呼び出した場合、最初に foo(int, ...)、次に foo(char *, ...)、最後に foo() と合致することになります。pack 演算子は、ゼロ個のパラメータも保持するので、前の例の場合は終端としての foo() が必要になってきます。この関数がないと、「foo() が見つからない」といったコンパイルエラーになります。

pack されたパラメータの個数は、sizeof... 演算子で取得できます。

auto counts = sizeof...(args);