mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-16 07:48:44 +01:00
85 lines
3.8 KiB
Text
85 lines
3.8 KiB
Text
Up to this point we've encountered templates defining a fixed number of
|
|
template parameters. However, templates may also defined as
|
|
hi(template: variadic)emi(variadic templates), allowing any number of
|
|
arguments to be passed to their instantiations.
|
|
|
|
Variadic templates are defined for function templates and for class
|
|
templates. Variadic templates allow us to specify an arbitrary number of
|
|
template arguments of any type.
|
|
|
|
Variadic templates were added to the language to prevent us from having to
|
|
define many overloaded templates and to be able to create em(type safe)
|
|
variadic functions.
|
|
|
|
Although bf(C) (and bf(C++)) support i(variadic functions), their use has
|
|
always been deprecated in bf(C++) as those functions are notoriously
|
|
type-em(un)safe. Variadic function templates can be used to process objects
|
|
that until now couldn't be processed properly by bf(C)-style variadic
|
|
functions.
|
|
|
|
Template headers of variadic templates use the phrase
|
|
hi(typename ...Params)tt(typename ...Params) (tt(Params) being a formal
|
|
name). A variadic class template tt(Variadic) could be declared as follows:
|
|
verb(
|
|
template<typename ...Params> class Variadic;
|
|
)
|
|
Assuming the class template's definition is available then this template
|
|
can be instantiated using any number of template arguments. Example:
|
|
verb(
|
|
class Variadic<
|
|
int,
|
|
std::vector<int>,
|
|
std::map<std::string, std::vector<int>>
|
|
> v1;
|
|
)
|
|
The template argument list of a variadic template can also be
|
|
empty. Example:
|
|
verb(
|
|
class Variadic<> empty;
|
|
)
|
|
If this is considered undesirable using an empty template argument list
|
|
can be prevented by providing one or more fixed parameters. Example:
|
|
verb(
|
|
template<typename First, typename ...Rest>
|
|
class tuple;
|
|
)
|
|
|
|
bf(C)'s function ti(printf) is a well-known example of a type-unsafe
|
|
function. It is turned into a type-safe function when it is implemented as a
|
|
variadic function template. Not only does this turn the function into a
|
|
type-safe function but it is also automatically extended to accept any type
|
|
that can be defined by bf(C++). Here is a possible declaration of a variadic
|
|
function template tt(printcpp):
|
|
verb(
|
|
template<typename ...Params>
|
|
void printcpp(std::string const &strFormat, Params ...parameters);
|
|
)
|
|
The i(ellipsis) (i(...)) used in the declaration serves two purposes:
|
|
itemization(
|
|
it() In the template header it is written to the em(left) of a template
|
|
parameter name where it declares a emi(parameter pack). A parameter
|
|
pack allows us to specify any number of template arguments when
|
|
instantiating the template. Parameter packs can be used to
|
|
bind type and non-type template arguments to template parameters.
|
|
it() In a template implementation it appears to the em(right) of the
|
|
template pack's parameter name. In that case it represents a series of
|
|
template arguments that are subsequently matched with a function
|
|
parameter that in turn is provided to the right of the ellipsis. Here
|
|
the ellipsis is known as the emi(unpack operator) as it `unpacks' a
|
|
series of arguments in a function's argument list thereby implicitly
|
|
defining its parameters.
|
|
)
|
|
bf(C++) offers no syntax to access the individual template arguments
|
|
directly. However, the arguments can be visited recursively. An example is
|
|
provided in the next section. The em(number)
|
|
hi(variadic template: number of arguments) of arguments is determined using a
|
|
new invocation of the ti(sizeof) operator:
|
|
verb(
|
|
template<typename ...Params>
|
|
struct StructName
|
|
{
|
|
enum: size_t { s_size = sizeof ...(Params) };
|
|
};
|
|
|
|
// StructName<int, char>::s_size -- initialized to 2
|
|
)
|