cppannotations/annotations/yo/classtemplates/variadic.yo

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
)