๐ŸŽ“ A1Learner
๐Ÿ”
0 of 28 lessons completed

C++ Variadic Templates

A variadic template is a template that takes a changing number of arguments. The extra arguments of a call form a pack that the template can work through.

One overload per count

The add job needs a separate overload for one, two, and three numbers. Each new count would need one more copy of the same idea.

#include <iostream>

int add(int a) {
  return a;
}

int add(int a, int b) {
  return a + b;
}

int add(int a, int b, int c) {
  return a + b + c;
}

int main() {
  std::cout << add(5) << std::endl;
  std::cout << add(5, 10) << std::endl;
  std::cout << add(5, 10, 20) << std::endl;
  return 0;
}

One fold replaces the overloads

The addAll template folds its pack with the + operator. Its three calls carry one, two, and four values and print the same three sums.

#include <iostream>

template <typename... Args>
auto addAll(Args... values) {
  return (values + ...);
}

int main() {
  std::cout << addAll(5) << std::endl;
  std::cout << addAll(5, 10) << std::endl;
  std::cout << addAll(2, 10, 20, 3) << std::endl;
  return 0;
}

sizeof... counts the pack

The countValues function prints the size of its pack. The first call carries two values and the second call carries four.

#include <iostream>

template <typename... Args>
void countValues(Args... values) {
  std::cout << sizeof...(values) << std::endl;
}

int main() {
  countValues(10, 20);
  countValues(10, 20, 30, 40);
  return 0;
}

A fold prints a row of values

The printRow fold writes each value of the pack with a space before every value after the first. The three values land on one line.

#include <iostream>

template <typename... Args>
void printRow(Args... values) {
  bool first = true;
  ((std::cout << (first ? "" : " ") << values, first = false), ...);
  std::cout << std::endl;
}

int main() {
  printRow(10, 20, 30);
  return 0;
}

Example

#include <iostream>

template <typename... Args>
double average(Args... values) {
  double total = (values + ...);
  return total / sizeof...(values);
}

int main() {
  std::cout << average(10, 20, 30) << std::endl;
  std::cout << average(4, 8) << std::endl;
  return 0;
}

Key points

  • A variadic template takes a changing number of arguments.
  • The arguments of one call form a parameter pack.
  • A fold expression combines every value in a pack with one operator.
  • The pattern (values + ...) adds every value in the pack.
  • sizeof... reports how many items a pack holds.
  • One fold can print every value of a pack in a single row.

In this example, average folds its pack into a total and divides by the pack size from sizeof.... The first call averages three values and lands on 20. The second call averages two values and lands on 6.

Note

One variadic template replaces a family of fixed overloads for different counts.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does sizeof...(values) give for the call addAll(5, 10, 20)?