{{Short description|Templates in computer programming}} {{Lacking overview|date=April 2026}} In computer programming, '''variadic templates''' or '''variation generics''' are templates that take a variable number of type parameters.

Variadic templates are supported by C++ (since the C++11 standard), and the D programming language. While other languages, such as Java or C# offer support for type-safe variadic functions, they do not offer the variadic generics support like that of C++ and D.

==C++== Prior to the introduction of variadic templates to C++, variadic functions could only be implemented using <code>va_list</code> or variadic macros from C, which lack type safety. The variadic template feature of C++ was designed by Douglas Gregor and Jaakko Järvi<ref>{{cite journal|author1=Douglas Gregor |author2=Jaakko Järvi |name-list-style=amp |title=Variadic Templates for C++0x|journal=Journal of Object Technology|volume= 7|issue=2, Special Issue OOPS Track at SAC 2007|date=February 2008|pages= 31–51 |doi=10.5381/jot.2008.7.2.a2 |url=http://www.jot.fm/issues/issue_2008_02/article2/}}</ref><ref>{{cite news|author1=Douglas Gregor |author2=Jaakko Järvi |author3=Gary Powell. |name-list-style=amp |title=Variadic templates. Number N1603=04-0043 in ISO C++ Standard Committee Pre-Sydney mailing|date=February 2004}}</ref> and was later standardized in C++11. Prior to C++11, templates (classes and functions) could only take a fixed number of arguments, which had to be specified when a template was first declared. C++11 allows template definitions to take an arbitrary number of arguments of any type. Thus, the only way to get type-safe variadic functions is thus through variadic templates over functions, as C++ lacks non-templated variadic functions like those of Java and C#.

<syntaxhighlight lang="cpp"> // takes zero or more arguments template <typename... Ts> class Tuple; </syntaxhighlight>

The above template class {{code|Tuple}} (representing a product type or tuple) will take any number of typenames as its template parameters. Here, an instance of the above template class is instantiated with three type arguments:

<syntaxhighlight lang="cpp"> using String = std::string; template <typename T> using Vector = std::vector<T>; template <typename K, typename V> using TreeMap = std::map<K, V>;

Tuple<int, Vector<int>, TreeMap<String, Vector<int>>> someInstanceName; </syntaxhighlight>

The number of arguments can be zero, so {{code|lang="cpp"|Tuple<> someInstanceName;}} will also work.

If the variadic template should only allow a positive number of arguments, then this definition can be used:

<syntaxhighlight lang="cpp"> // takes one or more arguments template <typename First, typename... Rest> class Tuple; </syntaxhighlight>

A common implementation of a tuple uses recursive decomposition like so: <syntaxhighlight lang="cpp"> // Forward declaration template <typename... Ts> class Tuple;

// Empty case template <> class Tuple<> {};

// Recursive case template <typename Head, typename... Tail> class Tuple<Head, Tail...> { private: Head head; Tuple<Tail...> tail; public: Tuple() = default; explicit Tuple(const Head& head, const Tail&... tail): head{head}, tail{tail...} {}

// ... }; </syntaxhighlight>

Variadic templates may also apply to functions, thus not only providing a type-safe add-on to variadic functions (such as {{mono|printf()}}), but also allowing a function called with <code>printf</code>-like syntax to process non-trivial objects.

<syntaxhighlight lang="cpp"> using std::string_view;

template <typename... Args> void myPrintf(string_view fmt, Args... parameters); </syntaxhighlight>

The ellipsis (...) operator has two roles. When it occurs to the left of the name of a parameter, it declares a parameter pack. Using the parameter pack, the user can bind zero or more arguments to the variadic template parameters. Parameter packs can also be used for non-type parameters. By contrast, when the ellipsis operator occurs to the right of a template or function call argument, it unpacks the parameter packs into separate arguments, like the {{code|args...}} in the body of {{code|printf}} below. In practice, the use of an ellipsis operator in the code causes the whole expression that precedes the ellipsis to be repeated for every subsequent argument unpacked from the argument pack, with the expressions separated by commas.

The fixed-point combinator is often implemented using variadic template arguments (note that <syntaxhighlight lang="cpp" inline>[](auto&&... args)</syntaxhighlight> is equivalent to <syntaxhighlight lang="cpp" inline>[]<template... Args>(Args&&... args)</syntaxhighlight>): <syntaxhighlight lang="cpp"> auto fix = [](auto f) { return [f](auto&&... args) -> decltype(auto) { return f(f, std::forward<decltype(args)>(args)...); }; };

auto factorial = fix([](auto self, long n) -> long { return n == 0 ? 1 : n * self(self, n - 1); });

std::println("5! = {}", factorial(5)); // prints 120 </syntaxhighlight>

To constrain the parameter to be only of type <code>T</code> (similar to <code>T... args</code>) in Java, one can use the concept <code>std::same_as</code><ref>{{Cite web|title=std::same_as|url=https://en.cppreference.com/cpp/concepts/same_as|author=cppreference.com|publisher=cppreference.com|website=cppreference.com|access-date=17 May 2026}}</ref> or <code>std::convertible_to</code> (for types which may be intended to be convertible).<ref>{{Cite web|title=std::convertible_to|url=https://en.cppreference.com/cpp/concepts/convertible_to|author=cppreference.com|publisher=cppreference.com|website=cppreference.com|access-date=17 May 2026}}</ref>

<syntaxhighlight lang="cpp"> using std::same_as;

// Equivalent to Java declaration // <T> void fn(T... args) template <typename T> void fn(same_as<T> auto... args) { // ... } </syntaxhighlight>

This can be further constrained to any specific type: <syntaxhighlight lang="cpp"> using std::convertible_to; using std::same_as; using std::string;

// Equivalent to Java declaration // void foo(int... args) void foo(same_as<int> auto... args) { // ... }

// Equivalent to Java declaration // void bar(String... args) void bar(convertible_to<string> auto... args) { // ... } </syntaxhighlight>

The use of variadic templates is often recursive. The variadic parameters themselves are not readily available to the implementation of a function or class. Therefore, the typical mechanism for defining something like a C++11 variadic {{code|printf()}} replacement would be as follows:

<syntaxhighlight lang="cpp"> using std::runtime_error;

// base case void myPrintf(const char s[]) { while (*s) { if (*s == '%') { if (*(s + 1) == '%') { ++s; } else { throw runtime_error("Invalid format string: missing arguments"); } } std::println("{}", *s++); } }

// recursive template <typename T, typename... Args> void myPrintf(const char s[], T value, Args... args) { while (*s) { if (*s == '%') { if (*(s + 1) != '%') { // pretend to parse the format: only works on 2-character format strings ( %d, %f, etc ); fails with %5.4f s += 2; // print the value std::println("{}", value); // called even when *s is 0 but does nothing in that case (and ignores extra arguments) myPrintf(s, args...); return; } ++s; } std::println("{}", *s++); } } </syntaxhighlight>

This is a recursive template. Notice that the variadic template version of {{code|myPrintf()}} calls itself, or (in the event that {{code|args...}} is empty) calls the base case.

There is no simple mechanism to iterate over the values of the variadic template. However, there are several ways to translate the argument pack into a single argument that can be evaluated separately for each parameter. Usually this will rely on function overloading, or — if the function can simply pick one argument at a time — using a dumb expansion marker:

<syntaxhighlight lang="cpp"> template <typename... Args> inline void pass(Args&&... args) { // ... } </syntaxhighlight>

which can be used as follows: <syntaxhighlight lang="cpp"> template <typename... Args> inline void expand(Args&&... args) { pass(someFunction(args)...); }

expand(42, "answer", true); </syntaxhighlight>

which will expand to something like: <syntaxhighlight lang="cpp"> pass(someFunction(arg1), someFunction(arg2), someFunction(arg3) /* etc... */ ); </syntaxhighlight>

The use of this "pass" function is necessary, since the expansion of the argument pack proceeds by separating the function call arguments by commas, which are not equivalent to the comma operator. Therefore, {{code|someFunction(args)...;}} will never work. Moreover, the solution above will only work when the return type of {{code|someFunction}} is not {{code|void}}. Furthermore, the {{code|someFunction}} calls will be executed in an unspecified order, because the order of evaluation of function arguments is undefined. To avoid the unspecified order, brace-enclosed initializer lists can be used, which guarantee strict left-to-right order of evaluation. An initializer list requires a non-{{code|void}} return type, but the comma operator can be used to yield {{code|1}} for each expansion element.

<syntaxhighlight lang="cpp"> struct Pass { template <typename... T> explicit Pass(T... args) { // ... } };

Pass{(someFunction(args), 1)...}; </syntaxhighlight>

Instead of executing a function, a lambda expression may be specified and executed in place, which allows executing arbitrary sequences of statements in-place.

<syntaxhighlight lang="cpp"> Pass{([&]() -> void { std::println("{}", args); }(), 1)...}; </syntaxhighlight>

However, in this particular example, a lambda function is not necessary. A more ordinary expression can be used instead:

<syntaxhighlight lang="cpp"> Pass{(std::println("{}", args), 1)...}; </syntaxhighlight>

In C++17, these can be rewritten using fold expressions on the comma operator:

<syntaxhighlight lang="cpp"> ([&]() -> void { std::println("{}", args); }(), ...); ((std::println("{}", args)), ...); </syntaxhighlight>

Another way is to use overloading with "termination versions" of functions. This is more universal, but requires a bit more code and more effort to create. One function receives one argument of some type ''and'' the argument pack, whereas the other receives neither. (If both had the same list of initial parameters, the call would be ambiguous, as a variadic parameter pack alone cannot disambiguate a call.) For example:

<syntaxhighlight lang="cpp"> void func() { // termination version }

template <typename First, typename... Args> void func(const First& first, const Args&&... args) { process(first); func(args...); // note: first does not appear here! } </syntaxhighlight>

If {{code|args...}} contains at least one argument, it will redirect to the second version — a parameter pack can be empty, in which case it will simply redirect to the termination version, which will do nothing.

Variadic templates can also be used in an exception specification, a base class list, or the initialization list of a constructor. For example, a class can specify the following:

<syntaxhighlight lang="cpp"> template <typename... BaseClasses> class ClassName : public BaseClasses... { public: explicit ClassName(BaseClasses&&... bases): BaseClasses(bases)... {} }; </syntaxhighlight>

The unpack operator will replicate the types for the base classes of {{code|ClassName}}, such that this class will be derived from each of the types passed in. Also, the constructor must take a reference to each base class, so as to initialize the base classes of {{code|ClassName}}.

With regard to function templates, the variadic parameters can be forwarded. When combined with universal references (see above), this allows for perfect forwarding:

<syntaxhighlight lang="cpp"> template <typename T> using SharedPtr = std::shared_ptr<T>;

template <typename T> struct SharedPtrAllocator { template <typename... Args> SharedPtr<T> construct(Args&&... params) { return SharedPtr<T>(new T(std::forward<Args>(params)...)); } }; </syntaxhighlight>

This unpacks the argument list into the constructor of <code>T</code>. The {{code|std::forward<Args>(params)}} syntax perfectly forwards arguments as their proper types, even with regard to rvalue-ness, to the constructor. The unpack operator will propagate the forwarding syntax to each parameter. This particular factory function automatically wraps the allocated memory in a {{code|std::shared_ptr}} for a degree of safety with regard to memory leaks.

Additionally, the number of arguments in a template parameter pack can be determined as follows:

<syntaxhighlight lang="cpp"> template <typename... Args> struct SizeCarrier { static constexpr size_t SIZE = sizeof...(Args); }; </syntaxhighlight>

The expression {{code|SizeCarrier<T, U>::SIZE}} will yield 2, while {{code|SizeCarrier<>::SIZE}} will give 0.

=== Variadic friends === In C++26, variadic friends were added to the language, which rely on variadic templates. <syntaxhighlight lang="cpp"> import std;

template <typename... Friends> class ClassWithFriends { private: int secretValue;

friend Friends...; public: explicit ClassWithFriends(int secret): secretValue{secret} {} };

class A { public: void readSecret(const class ClassWithFriends<A, B>& instance) const { std::println("Inspecting secret value from A: {}", instance.secretValue); } };

class B { public: void readSecret(const class ClassWithFriends<A, B>& instance) const { std::println("Inspecting secret value from B: {}", instance.secretValue); } };

int main(int argc, char* argv[]) { ClassWithFriends<A, B> secretHolder(135); A a; B b; a.readSecret(secretHolder); b.readSecret(secretHolder); } </syntaxhighlight>

=== Pack indexing === Pack indexing was introduced to C++ in C++26, which retrieves a type or value at a specified index of a pack with a less{{explain|date=April 2026}} recursive syntax, while the index is required to be a constant expression.<ref name ="cppref">{{cite web |last= |first= |date= 16 April 2025 |title= Pack indexing (since C++26) |url= https://en.cppreference.com/w/cpp/language/pack_indexing.html |website=cppreference.com |location= |publisher=|access-date= 29 March 2026}}</ref> The syntax of pack indexing is <code>''id-expression''...[''expression'']</code>.

<syntaxhighlight lang="c++"> import std;

using std::index_sequence; using std::index_sequence_for; using std::tuple;

// This function, reversed(), takes any number of arguments and returns a // tuple<Ts...> containing the same arguments in reversed order with each // T in Ts... decayed as decay_t<T>. template <typename... Ts> requires (sizeof...(Ts) > 0) constexpr auto reversed(Ts&&... args) noexcept { constexpr size_t MAX_INDEX_SIZE = sizeof...(args) - 1; auto reverser = [&args...]<size_t... Is>(index_sequence<Is...>) { auto reverseForOneIndex = [&args...]<size_t I> { return args...[MAX_INDEX_SIZE - I]; }; return std::make_tuple(reverseForOneIndex.template operator()<Is>()...); }; return reverser(index_sequence_for<Ts...>{}); }

int main() { // type of result: // tuple<char, long double, double, float, const char*, int> constexpr tuple result = reversed(13, "hello", 2.718f, 3.14, 9.9375L, 'X'); static_assert(std::get<0>(result) == 'X'); }

</syntaxhighlight>

=== Iterating over type and parameter packs === C++26 adds expansion statements, declared with <code>'''template for''' (''init_stmt''<sub>opt</sub>; ''for-range-declaration'' : ''expansion-initializer'') ''compound-stmt''</code> to iterate over <code>std::tuple<Ts...></code>, collection types like <code>std::array<T, N></code> and <code>std::vector<T></code>, and type/parameter packs (<code>Ts... args</code>).<ref name="expansion_statements">{{Cite web|title=Expansion statements|url=https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p1306r5.html|publisher=WG21|website=open-std.org|author=Dan Katz|date=20 June 2025}}</ref>

<syntaxhighlight lang="c++"> import std;

void printAllObjects(auto&&... args) { template for (auto&& arg : {args...}) { std::print("{}", arg); } }

int main() { printAllObjects("13 + 31 = ", 44, "\nHello, world!\n", 3.14, '\n', 2.718f, '\n', 735.9572L, false); return 0; } </syntaxhighlight>

Expansion statements allow for {{code|break}} and {{code|continue}} control flow statements, which behave the same as in any other loop.<ref name="expansion_statements"/> <syntaxhighlight lang="cpp"> import std;

using std::index_sequence; using std::index_sequence_for;

template <typename... Ts> constexpr bool areEvenIndicesEven(Ts&&... args) noexcept { auto checkEvenIndices = [&args...]<size_t... Is>(maybe_unused index_sequence<Is...> s) -> bool { template for (constexpr size_t I : {Is...}) { if constexpr (I % 2 != 0) { continue; } if (args...[I] % 2 != 0) { return false; } } return true; }; return checkEvenIndices(index_sequence_for<Ts...>{}); }

int main() { static_assert(areEvenIndicesEven(0, 1, 2, 3)); } </syntaxhighlight>

== Carbon == Carbon, a language designed with interoperability with C++ in mind, offers variadics, in particular pack expansions.<ref>{{Cite web|title=Variadics - Carbon Language documentation|url=https://docs.carbon-lang.dev/docs/design/variadics.html|publisher=Carbon Language Project|author=Carbon Language Project|date=1 April 2026|website=docs.carbon-lang.dev}}</ref> <syntaxhighlight lang="carbon"> // Takes an arbitrary number of vectors with arbitrary element types, and // returns a vector of tuples where the i-th element of the vector is // a tuple of the i-th elements of the input vectors. fn Zip[... each ElementType:! type](... each vector: Vector(each ElementType)) -> Vector((... each ElementType)) { ... var each iter: auto = each vector.Begin(); var result: Vector((... each ElementType)); while (...and each iter != each vector.End()) { result.push_back((... each iter)); ... each iter++; } return result; } </syntaxhighlight>

== D == {{No citations section|date=May 2026}}

=== Definition ===

The definition of variadic templates in D is similar to their C++ counterpart: <syntaxhighlight lang="d"> template VariadicTemplate(Args...) { // body here... } </syntaxhighlight>

Likewise, any argument can precede the argument list: <syntaxhighlight lang="d"> template VariadicTemplate(T, string value, alias symbol, Args...) { // body here... } </syntaxhighlight>

=== Basic usage ===

Variadic arguments are very similar to constant array in their usage. They can be iterated upon, accessed by an index, have a {{code|length}} property, and can be sliced. Operations are interpreted at compile time, which means operands can't be runtime value (such as function parameters).

Anything which is known at compile time can be passed as a variadic arguments. It makes variadic arguments similar to [http://dlang.org/template#TemplateAliasParameter template alias arguments], but more powerful, as they also accept basic types (char, short, int...).

Here is an example that prints the string representation of the variadic parameters. {{code|StringOf}} and {{code|StringOf2}} produce equal results. <syntaxhighlight lang="d"> static int staticInt;

struct Dummy {}

void main() { pragma(msg, StringOf!("Hello world", uint, Dummy, 42, staticInt)); pragma(msg, StringOf2!("Hello world", uint, Dummy, 42, staticInt)); }

template StringOf(Args...) { enum StringOf = Args[0].stringof ~ StringOf!(Args[1..$]); }

template StringOf() { enum StringOf = ""; }

template StringOf2(Args...) { static if (Args.length == 0) { enum StringOf2 = ""; } else { enum StringOf2 = Args[0].stringof ~ StringOf2!(Args[1..$]); } } </syntaxhighlight>

Outputs: <syntaxhighlight lang="text"> "Hello world"uintDummy42staticInt "Hello world"uintDummy42staticInt </syntaxhighlight>

=== AliasSeq ===

Variadic templates are often used to create a sequence of aliases, named [https://dlang.org/phobos/std_meta.html#AliasSeq AliasSeq]. The definition of an AliasSeq is actually very straightforward: <syntaxhighlight lang="d"> alias AliasSeq(Args...) = Args; </syntaxhighlight>

This structure allows one to manipulate a list of variadic arguments that will auto-expand. The arguments must either be symbols or values known at compile time. This includes values, types, functions or even non-specialized templates. This allows any operation you would expect:

<syntaxhighlight lang="d"> import std.meta;

void main() { // Note: AliasSeq can't be modified, and an alias can't be rebound, so we'll need to define new names for our modifications. alias numbers = AliasSeq!(1, 2, 3, 4, 5, 6); // Slicing alias lastHalf = numbers[$ / 2 .. $]; static assert(lastHalf == AliasSeq!(4, 5, 6)); // AliasSeq auto expansion alias digits = AliasSeq!(0, numbers, 7, 8, 9); static assert(digits == AliasSeq!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)); // std.meta provides templates to work with AliasSeq, such as anySatisfy, allSatisfy, staticMap, and Filter. alias evenNumbers = Filter!(isEven, digits); static assert(evenNumbers == AliasSeq!(0, 2, 4, 6, 8)); }

template isEven(int number) { enum isEven = (0 == (number % 2)); } </syntaxhighlight>

== Related implementations == In C#/.NET, the class <code>System.Tuple</code> has specific instantiations for 1 to 8 elements. In order to create a tuple with nine or more components, the final parameter <code>TRest</code> of <code>Tuple<T1, T2, T3, T4, T5, T6, T7, TRest></code> is supplied as another tuple, as C# lacks variadic template parameters.<ref>{{Cite web|title=Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> Class|url=https://learn.microsoft.com/en-us/dotnet/api/system.tuple-8|website=learn.microsoft.com|publisher=Microsoft Learn|access-date=14 October 2025}}</ref>

In Java, one can emulate variadic parameters using the top type <code>java.lang.Object</code> (similarly in C#/.NET, with <code>System.Object</code>) however this lacks the type-safety of C++-style variadic parameters. <syntaxhighlight lang="java"> import java.util.List;

void printAllObjects(Object... args) { for (Object arg : args) { System.out.println(arg); } }

void main() { printAllObjects("Hello, world!", 42, 3.14159f, true, List.of(1, 2, 3)); } </syntaxhighlight>

Proposals for variadic generics have existed in Rust since 2013<ref>{{Cite web|title=Variadic Generics|url=https://github.com/rust-lang/lang-team/blob/master/src/design_notes/variadic_generics.md|author=The Rust Team|website=github.com|publisher=The Rust Team|date=12 July 2023}}</ref>, but as of yet have not been added to the language. However, these can be similarly emulated using variadic macros, which may be used for code generation.<ref>{{Cite web|title=Variadic Interfaces|url=https://doc.rust-lang.org/rust-by-example/macros/variadics.html|publisher=Rust by Example|author=The Rust Team|website=rust-lang.org|date=1 April 2026}}</ref>

== See also == For articles on variadic constructs other than templates * Variadic function * Variadic macro in the C preprocessor

== References == {{reflist}}

==External links== *[http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf Working draft for the C++ language, January 16, 2012] *[http://dlang.org/variadic-function-templates.html Variadic Templates in D language]

Category:Computer programming Category:Articles with example C++ code Category:Articles with example D code