← Back to C++ Course | Chapter 11: Templates | Lesson 5 of 5

C++ Variadic Templates

What are Variadic Templates?

Variadic templates accept a variable number of arguments of arbitrary, potentially different types, giving you a type-safe, compile-time-checked alternative to old C-style variable arguments (like printf's ...).

Example: What are Variadic Templates?

cpp
#include <iostream>

template <typename... Args>
void printAll(Args... args) {
	(std::cout << ... << args) << std::endl;
}

int main() {
	printAll(1, 2.5, "text");
	return 0;
}

Parameter Packs

The ellipsis symbol (...) declares what's called a parameter pack, which can stand in for any number of template type parameters or function arguments — zero, one, or many — determined entirely by how the template is actually used.

Example: Parameter Packs

cpp
#include <iostream>

template <typename... Args>
int countArgs(Args... args) {
	return sizeof...(args);
}

int main() {
	std::cout << countArgs(1, 2, 3, 4) << std::endl;
	return 0;
}

Recursive Pack Expansion

To process the contents of a parameter pack, you typically unpack it recursively: the function handles the first argument, then calls itself again with the rest of the pack, peeling off one argument per recursive call until none remain.

Example: Recursive Pack Expansion

cpp
#include <iostream>

void printAll() {}

template <typename T, typename... Rest>
void printAll(T first, Rest... rest) {
	std::cout << first << " ";
	printAll(rest...);
}

int main() {
	printAll(1, 2, 3);
	std::cout << std::endl;
	return 0;
}

Defining Base Cases

Recursive variadic templates need a base-case overload to actually stop the recursion — typically a version of the function that takes zero arguments — which the compiler selects once the parameter pack has been fully consumed.

Example: Defining Base Cases

cpp
#include <iostream>

void printAll() {
	std::cout << std::endl; // base case: stops the recursion
}

template <typename T, typename... Rest>
void printAll(T first, Rest... rest) {
	std::cout << first << " ";
	printAll(rest...);
}

int main() {
	printAll(1, 2, 3);
	return 0;
}

Variadic Struct Nesting

Parameter packs can also be expanded inside struct definitions, which is exactly the technique the standard library uses internally to implement variable-length structures like std::tuple.

Example: Variadic Struct Nesting

cpp
#include <iostream>

template <typename... Types>
struct Tuple {};

template <typename First, typename... Rest>
struct Tuple<First, Rest...> {
	First value;
	Tuple<Rest...> rest;
};

int main() {
	Tuple<int, double> t;
	t.value = 5;
	t.rest.value = 3.14;
	std::cout << t.value << " " << t.rest.value << std::endl;
	return 0;
}
🔒

Chapter Quiz — Complete all 5 topics to unlock

0/5 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.