В програмуванні, варіативний шаблон — шаблон зі змінною кількістю аргументів.
Варіативні шаблони підтримуються мовою C++ (починаючи з стандарту C++11), та мовою програмування D.
Синтаксис варіативного шаблону в мові C++11 в загальному випадку наступний:
template<typename... Values> class tuple; // нуль або більше аргументів
Якщо потрібно заборонити використання шаблону без параметрів, то використовують наступний підхід, що вимагає використання як мінімум одного параметра:
template<typename First, typename... Rest> class tuple; // один або більше аргументів
Варіативні шаблони також можуть застосовуватися з функціями: template<typename... Params> void printf(const std::string &str_format, Params... parameters);
Часто використовують рекурсивний виклик варіативних шаблонів. Самі варіаційні параметри не є доступними для реалізації функції або класу. Тому для реалізації заміни звичного printf через варіативний шаблон у C++11 типовим підходом буде такий: // базовий варіант void printf(const char *s) { while (*s) { if (*s == '%') { if (*(s + 1) == '%') { ++s;
else { throw std::runtime_error("неправильний формат рядка: відсутні аргументи");
std::cout << *s++;
// рекурсивний template<typename T, typename... Args> void printf(const char *s, T value, Args... args) { while (*s) { if (*s == '%') { if (*(s + 1) == '%') { ++s;
else { std::cout << value; s += 2; // зрозуміло, що це працюватиме лише з 2-х символьними специфікаторами ( %d, %f, і т.п. ); але не з %5.4f і т.п. printf(s, args...); // буде викликатися навіть для *s рівного nullptr, але не робитиме нічого, просто ігноруватиме аргументи return;
std::cout << *s++;
Зауважте, що побудована з застосуванням варіативного шаблону версія printf викликає себе рекурсивно або (коли список аргументів args… буде порожній) викликає базовий варіант.
Приклад
Приклад короткої програми на мові С++ де застосовано варіативний шаблон, що підраховує суму змінного числа аргументів: #include <iostream>
template<typename T> T SUM(T v) { return v; }
template<typename T, typename T1, typename... Ts> T SUM(T v, T1 v1, Ts... vs) { return v + SUM(v1, vs...); }
int main(int argc, char**) { std::cout << SUM(2, 2) << std::endl; std::cout << SUM(argc, 1, 2, 3) << std::endl; }
Вирази згортання і варіативні шаблони У стандарті C++17 з'явились вирази згортання (), що значно полегшують використання технології варіативних шаблонів. Наприклад, з їх використанням код функції SUM може мати такий вигляд://Універсальні посилання на кожен з параметрів
template<typename ...Ts> auto SUM(Ts&& ... param) { //Зверніть увагу: 0 виступає в ролі нейтрального значення return (std::forward<Ts>(param) + ... + 0); //Приймає вигляд (param1 + (param2 + (...(0))) }
Розглянемо можливий виклик функції:#include <iostream>
int main(int argc, char *argv[]) { constexpr int a = 100; std::cout<<SUM(10, 20, a); //Результат: 130 }
Див. також Варіативна функція Варіативний макрос