Кратко

  • Вариативные выражения облегчают выполнение одинаковых операций над всеми аргументами пакета параметров, упрощая и сокращая код.
  • Вариативные индексы полезны для итерации и доступа к элементам пакета параметров, особенно при работе с кортежами и другими структурами данных.
  • Вариативные базовые классы позволяют создавать классы с множественным наследованием, что делает код более гибким и универсальным.

Вариативные выражения (Variadic Expressions)

Вариативные выражения позволяют применять операторы к каждому элементу пакета параметров. Эти выражения часто используются для выполнения однородных операций над всеми аргументами пакета.

Пример 1: Суммирование аргументов

#include <iostream>
 
template<typename... Args>
auto sum(Args... args) {
    return (args + ...); // Правосторонняя свертка
}
 
int main() {
    std::cout << sum(1, 2, 3, 4, 5) << std::endl; // Output: 15
    return 0;
}

Пример 2: Вывод аргументов

#include <iostream>
 
template<typename... Args>
void print(Args... args) {
    (std::cout << ... << args) << std::endl; // Правосторонняя свертка
}
 
int main() {
    print(1, 2, 3);             // Output: 123
    print("Hello, ", "world!"); // Output: Hello, world!
    return 0;
}

Вариативные индексы (Variadic Indexes)

Вариативные индексы (variadic indexes) используются в шаблонах для обработки индексов параметров пакета. Это полезно для итерации и доступа к элементам пакета параметров.

Пример: Доступ к элементам std::tuple

#include <iostream>
#include <tuple>
#include <utility>
 
template<typename Tuple, std::size_t... Is>
void printTuple(const Tuple& t, std::index_sequence<Is...>) {
    ((std::cout << std::get<Is>(t) << " "), ...) << std::endl; // Правосторонняя свертка
}
 
template<typename... Args>
void printTuple(const std::tuple<Args...>& t) {
    printTuple(t, std::index_sequence_for<Args...>{});
}
 
int main() {
    auto t = std::make_tuple(1, 2.5, "example");
    printTuple(t); // Output: 1 2.5 example 
    return 0;
}

Вариативные базовые классы (Variadic Base Classes)

С помощью вариативных шаблонов можно указать несколько базовых классов для одного класса. Это помогает создавать обобщенные классы с множественным наследованием.

Пример: Класс с множественным наследованием

#include <iostream>
 
template<typename... Bases>
class Derived : public Bases... {
public:
    Derived(const Bases&... bases) : Bases(bases)... {}
 
    void show() {
        (Bases::show(), ...); // Правосторонняя свертка
    }
};
 
class Base1 {
public:
    void show() const {
        std::cout << "Base1" << std::endl;
    }
};
 
class Base2 {
public:
    void show() const {
        std::cout << "Base2" << std::endl;
    }
};
 
int main() {
    Derived<Base1, Base2> d(Base1(), Base2());
    d.show(); // Output: Base1 Base2
    return 0;
}