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

C++ Variadic Templates

A variadic template accepts any number of inputs of any types, like a bag that stretches to hold whatever you put in. It unpacks them one by one.
Syntax
cpp
template <typename... Args>
void function_name(Args... args) {
  // sizeof...(args) is the number of arguments
}

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 std::cout and std::cin
#include <iostream>

// Declare a template so this works with any suitable type
template <typename... Args>
void printAll(Args... args) {
	(std::cout << ... << args) << std::endl;
}

// Program execution starts in main()
int main() {
	printAll(1, 2.5, "text");
	// Return 0 to signal that the program finished successfully
	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 std::cout and std::cin
#include <iostream>

// Declare a template so this works with any suitable type
template <typename... Args>
int countArgs(Args... args) {
	// Send sizeof...(args) back to the caller
	return sizeof...(args);
}

// Program execution starts in main()
int main() {
	// Print to the console with cout
	std::cout << countArgs(1, 2, 3, 4) << std::endl;
	// Return 0 to signal that the program finished successfully
	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 std::cout and std::cin
#include <iostream>

void printAll() {}

// Declare a template so this works with any suitable type
template <typename T, typename... Rest>
void printAll(T first, Rest... rest) {
	// Print to the console with cout
	std::cout << first << " ";
	printAll(rest...);
}

// Program execution starts in main()
int main() {
	printAll(1, 2, 3);
	// Print to the console with cout
	std::cout << std::endl;
	// Return 0 to signal that the program finished successfully
	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 std::cout and std::cin
#include <iostream>

// Declare a template so this works with any suitable type
template <typename... Types>
// Define a structure type named Tuple
struct Tuple {};

// Declare a template so this works with any suitable type
template <typename First, typename... Rest>
struct Tuple<First, Rest...> {
	First value;
	Tuple<Rest...> rest;
};

// Program execution starts in main()
int main() {
	Tuple<int, double> t;
	t.value = 5;
	t.rest.value = 3.14;
	// Print to the console with cout
	std::cout << t.value << " " << t.rest.value << std::endl;
	// Return 0 to signal that the program finished successfully
	return 0;
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Forgetting the base case for recursive pack expansion, which fails to compile.
  2. Putting the ... in the wrong place when declaring or expanding a pack.
  3. Confusing sizeof...(args) with sizeof(args).
Chapter Summary
  • Templates let you write code that works with different types.
  • Function templates and class templates generate type-specific code as needed.
  • Template specialization and variadic templates handle special cases and variable numbers of arguments.
🔒

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.