Variadic templates (вариативные шаблоны) — мощная возможность C++, позволяющая работать с произвольным количеством аргументов шаблона. Вот профессиональный разбор их применения.
Объявление вариативного шаблона:
template<typename... Args>
void myFunction(Args... args) {
// Обработка args...
}
Где ...
указывает на то, что шаблон или функция принимает переменное количество аргументов.
// Базовый случай рекурсии
void process() {}
template<typename T, typename... Args>
void process(T first, Args... rest) {
handleSingle(first); // Обработка первого аргумента
process(rest...); // Рекурсивный вызов для остальных
}
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // Распаковка с оператором +
}
void safePrint(const char* s) {
while (*s) {
if (*s == '%' && *(++s) != '%')
throw std::runtime_error("invalid format string");
std::cout << *s++;
}
}
template<typename T, typename... Args>
void safePrint(const char* s, T value, Args... args) {
while (*s) {
if (*s == '%' && *(++s) != '%') {
std::cout << value;
return safePrint(++s, args...);
}
std::cout << *s++;
}
throw std::runtime_error("extra arguments provided");
}
template<typename... Types>
class Tuple;
template<typename Head, typename... Tail>
class Tuple<Head, Tail...> : private Tuple<Tail...> {
Head head;
public:
Head& getHead() { return head; }
Tuple<Tail...>& getTail() { return *this; }
};
template<>
class Tuple<> {}; // Базовый случай
template<typename... Args>
constexpr size_t countArgs(Args... args) {
return sizeof...(Args); // или sizeof...(args)
}
template<typename T, typename... Args>
struct contains : std::false_type {};
template<typename T, typename... Args>
struct contains<T, T, Args...> : std::true_type {};
template<typename T, typename U, typename... Args>
struct contains<T, U, Args...> : contains<T, Args...> {};
template<typename... Args>
void wrapper(Args&&... args) {
target(std::forward<Args>(args)...);
}
template<typename... Bases>
class VariadicDerived : public Bases... {
public:
VariadicDerived(const Bases&... bases) : Bases(bases)... {}
};
template<typename... Args,
typename = std::enable_if_t<(std::is_integral_v<Args> && ...)>>
void integralSum(Args... args) {
// Только для целочисленных типов
}
template<typename...>
struct MyStruct;
template<typename First, typename... Rest>
struct MyStruct<First, Rest...> {
// Специализация для одного и более аргументов
};
template<>
struct MyStruct<> {
// Специализация для нуля аргументов
};
template<typename... Args>
constexpr auto allTrue(Args... args) {
return (args && ...);
}
template<typename... Args>
void processWithLambda(Args... args) {
auto lambda = [](auto... params) {
// Обработка params...
};
lambda(args...);
}
Variadic templates позволяют:
Ключевые техники:
Используйте variadic templates для:
Помните о балансе между гибкостью и сложностью кода. Variadic templates — мощный инструмент, но его избыточное использование может ухудшить читаемость.