С++ Шаблоны с переменным числом параметров

Шаблон с переменным числом аргументов ( С++11 ) - это шаблон класса или функции, поддерживающий произвольное число аргументов. Этот механизм особенно удобен для разработчиков библиотек C++, поскольку его можно применить к как к шаблонам классов, так и к шаблонам функций. Таким образом, он предоставляет широкий спектр широкий спектр типобезопасных и нетривиальных функций и гибких возможностей.

Подробнее : C++ Parameter pack
Еще : Многоточия и шаблоны с переменными аргументами

В шаблонах с переменным числом аргументов многоточие используется двумя способами. слева от имени параметра оно означает пакет параметров, а справа от имени параметра оно служит для развертывания пакетов параметров в отдельные имена.

template<typename ... Arguments> 
class classname;  

В приведенном выше примере параметр Arguments означает пакет параметров. При инстанцировании класс classname может принимать переменное число аргументов, как показано в следующих примерах:

 template<typename ... Arguments> 
 class vtclass;  

vtclass< > vtinstance1;  
vtclass<int> vtinstance2;  
vtclass<float, bool> vtinstance3;  
vtclass<long, std::vector<int>, std::string> vtinstance4;  

Кроме того, определение шаблонного класса с переменным числом аргументов может устанавливать требование, что должен быть передан по меньшей мере один параметр:

template <typename First, typename ... Rest> 
class classname; 

Ниже представлен простейший пример синтаксиса для определения шаблонной функции с переменным числом аргументов.

template <typename ... Arguments> 
returntype functionname(Arguments ... args);  

Далее пакет параметров Arguments развертывается для использования, что бы показать что функция принимает переменное число аргументов.

Возможны и другие формы синтаксиса шаблонной функции с переменным количеством аргументов:

template <typename... Arguments> returntype functionname(Arguments &   ... args);   
template <typename... Arguments> returntype functionname(Arguments && ... args);  
template <typename... Arguments> returntype functionname(Arguments *   ... args); 
template <typename... Arguments> returntype functionname(const Arguments & ... args);  

Шаблонные функции с переменным числом аргументов (как и аналогичные шаблонные классы) также могут устанавливать требование о том, что должен быть передан по меньшей мере один параметр.

template <typename First, typename... Rest>
returntype functionname(const First& first, const Rest&... args); 

В шаблонах с переменным числом аргументов используется оператор sizeof...() (он не имеет отношения к старому оператору sizeof()):

template<typename ... Arguments>
void tfunc(const Arguments & ... args)
{   
    const unsigned numargs = sizeof ... (Arguments);
    cout << numargs << "\n";
}

tfunc(11, 2.5, "asd"); // 3

Неоднозначности:

В списке-параметров-шаблона (template ) параметр typename... вводит в программу пакет параметров шаблона.

В предложении объявления параметра (func(parameter-list)) многоточие "верхнего уровня" вводит пакет параметров функции, и положение многоточия имеет большое значение.

template <typename ... Types> void func1(std::vector<Types ... > v1);
// не тоже самое !!!
template <typename ... Types> void func2(std::vector<Types> ... v2);  

Пример проброса значений во внутренние ф-ции:

// Функция которая принимает конкретные аргументы
void inner2(int a, int b, int c)
{
    cout << "a = " << a << endl
         << "b = " << b << endl
         << "c = " << c << endl;
}

// Функция обертка принимает переменное кол-во аргументов
template<class ... T> // вводим пакет параметров шаблона
void wrapper2(T ... args) // вводит пакет параметров функции
{
    inner2(args... );
}

int main(int argc, char* argv[])
{
    wrapper2(1, 2, 3);
    return 0;
}

С использованием std::forward

// Функция которая принимает конкретные аргументы
void inner(double a, char b, int c, const string & d)
{
    cout << "a = " << a << endl
         << "b = " << b << endl
         << "c = " << c << endl
         << "d = " << d << endl;
}

// Функция обертка принимает переменное кол-во аргументов
template<class ... Args> // вводим пакет параметров шаблона
void wrapper(Args && ... args) // вводит пакет параметров функции
{
    inner( std::forward<Args>(args)... );
}

void inner2(int a, int b, int c)
{
    cout << "a = " << a << endl
         << "b = " << b << endl
         << "c = " << c << endl;
}

int main(int argc, char* argv[])
{
    wrapper(123.5, 'w', 777, "Hello World");
    return 0;
}