Classic templates had a fixed number of arguments. However, in some use cases, it is desirable to have the same function or class template for varying numbers of template parameters. It was possible to achieve some automation by using macros, e. Preprocessor, but it takes some masochistic tendencies to learn the necessary techniques. In addition, those macros had the usual weaknesses of not being debuggable.
A parameter pack is simply a name assigned to a list of template parameters instead to a single parameter. There are three kinds of template parameters, and there is a way to define a parameter pack instead of a single template parameter for all three of them. We can also mix single parameters and parameter packs, with the restriction, that there may only be a single parameter pack definition, and it has to be at the end of the parameter list:. You notice that I use names like Ts , Ns and Us for parameter packs.
You will also often see names like Args. It is just a good naming convention, but not required, to use plural names for parameter packs. In addition to template parameter packs we have function parameter packs. They are defined when in a variadic function template the template parameter pack is used to define function arguments. Sounds complicated, but an example will clear this up:.
We have two template functions: first taking single parameter and second taking… exactly what? Template parameter pack defines a list of unspecified possibly different types that will be used to instantiate this template function.
Function parameter pack is using the same list of types to create the function argument list. The difference and real strength of variadic templates comes in the argument expansion. The reason for having the first argument explicitly stated and having an overload will be explained later. When compiler sees an ellipsis in the template it automatically expands the expression that uses it into a comma-separated list according to the context.
In our example we have three different places where And now the best of it: 1. All happens at compile time no runtime cost and allows optimizations! All types are preserved ensuring type safety! However, the drawback of this solution is a different approach to implementing the function. This requires a bit of a mindset switch and time to get used to it. And now is the time to explain the implementation of our adding function. The idea is to use the recursion, extract the first parameter from the argument pack in each call and pass the rest to the next iteration.
The rule of thumb is "Expansion can generate a list of , -separated patterns where , is a list delimiter. To call a function for each argument, you can use recursion which is the primary tool in the variadic template programmer's box :. I won't go into rvalue-references, but to somebody working with variadic templates; universal references are a god-send. One of the uses of std::forward and universal references are perfect forwarding of types to other functions. To get around this, we specify a forwarding function to take any type of reference to a variable rvalue or lvalue.
Then, to be sure that we pass the exact type passed in the forwarding function we use std::forward , then and only then do we allow the demoting of types; because we are now at the point where it matters most. If you need to, read more on universal references and perfect forwarding ; Scott Meyers is pretty great as a resource. Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams?
Collectives on Stack Overflow. Learn more. Variadic template pack expansion Ask Question. Asked 7 years, 4 months ago. Active 2 years, 10 months ago. Viewed 47k times. Improve this question. Username 3 3 silver badges 13 13 bronze badges.
Viacheslav Dronov Viacheslav Dronov 1 1 gold badge 7 7 silver badges 11 11 bronze badges. What if Args was empty? Add a comment. Active Oldest Votes.
Improve this answer. Barry k 28 28 gold badges silver badges bronze badges.
0コメント