Варіативний шаблон

В програмуванні, варіативний шаблон — шаблон зі змінною кількістю аргументів.

Варіативні шаблони підтримуються мовою 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 з'явились вирази згортання (англ. fold expressions), що значно полегшують використання технології варіативних шаблонів. Наприклад, з їх використанням код функції SUM може мати такий вигляд:

template<typename ...Ts> //C++17

//Універсальні посилання на кожен з параметрів

auto SUM(Ts&& ... param){

return (std::forward<Ts>(param) + ... + 0); //Приймає вигляд (param1 + (param2 + (...(0)))

//Зверніть увагу: 0 виступає в ролі нейтрального значення

}

Розглянемо можливий виклик функції:

int main(int argc, char *argv[])

{

constexpr int a = 100;

std::cout<<SUM(10, 20, a); //Результат: 130

}

Див. такожРедагувати