I learned some time ago that you can create templates with zero parameters. While it is not possible to create them directly, you can use member templates
template<typename ...T>
struct Maker {
template<T...>
struct HasNParams { };
};
Maker<>::HasNParams<> hnp;
I wonder whether this is intended to be well-formed and what you can do with these beasts. Can you pass them as template arguments, and create explicit specializations (I guess the only scenario is for the empty case then)?
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)
Template non-type arguments in C++It is also possible to use non-type arguments (basic/derived data types) i.e., in addition to the type argument T, it can also use other arguments such as strings, function names, constant expressions, and built-in data types.
8. Why we use :: template-template parameter? Explanation: It is used to adapt a policy into binary ones. 9.
At the risk of sounding obvious, ending recursive instantiation.
template<typename Arg, typename ...T>
struct Maker : public Maker<T...>
{
template<T...>
struct HasNmin1Params { };
};
The point here is that the actual argument list to Maker
isn't empty, but we only use N-1 arguments in HasNminOneParams
.
Consider the following class template:
template <typename... > struct typelist { };
This is the metaprogramming equivalent of a container. And in the same way that it is useful to have an empty vector
or map
, it is useful to have an empty typelist
. That is, something of type typelist<>
. Here are two example use-cases for such a construct.
It could be the termination condition for type recursion:
void foo(typelist<> ) { }
template <typename T, typename... Ts>
void foo(typelist<T, Ts...> ) {
bar<T>();
foo(typelist<Ts...>{});
}
It could be a "return" value for a metafunction, indicating a failure condition.
template <typename F, typename T>
struct filter_one
: std::conditional_t<F::template apply<T>::value,
typelist<T>,
typelist<>>
{ };
Which is a helper we could use to write a typelist filter metafunction:
template <typename F, typename TL>
struct filter;
template <typename F, typename... Ts>
struct filter<F, typelist<Ts...>>
: concat_t<filter_one<F, Ts>...>
{ };
Both of those are very useful features of typelist<>
, and that's just the one class template.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With