全て同じ型の可変引数を受け取る関数の指定方法は 2 つあります。
ひとつは、可変引数テンプレートと SameType コンセプトを使用する方法
template <typename T, BinaryPredicate<T, T> Compare, typename ... Args> requires SameType<T, Args...> const T& min(const T& a, const T& b, const Args&... args, Compare comp);
int i = min(1, 2, a, b, 34, comp);
もうひとつは、 initializer_list を使用する方法
template <typename T, BinaryPredicate<T, T> Compare> const T& min(initializer_list<T> values, Compare comp);
int i = min({1, 2, a, b, 34}, comp);
こういった場合にどちらを使用するのがいいかという議論があって
・可変引数テンプレートは要素の数をコンパイル時に知ることができるが、 initializer_list はできない
・可変引数テンプレートはテンプレートを使用するので、仮想関数や動的ライブラリには不適当かもしれない
・initializer_list 版は 2 文字多く入力する必要がある( '{' と '}' )
・可変引数テンプレートは、パラメータの組み合わせによっては、テンプレートのインスタンス化によってコードが膨れあがる
・引数がリテラルの場合のパフォーマンスは基本的にどちらも同じ
・initializer_list 版は基本的にループを使用するが、可変引数テンプレートはコンパイル時に展開される
・initializer_list は内部のデータを move できないので可変引数を受け取る側にコストが発生する
・gcc で int と std::string(30文字) を使用して min 関数のベンチマークを取ったら initializer_list 版のほうが速かった
結論としては、コンパイル時に要素数を知る必要がないのであれば、
明瞭な構文とよりよいパフォーマンスを提供する initializer_list 版を使用することを推奨するそうです。
N2722 Variadic functions: Variadic templates or initializer lists?