We have this little metaprogramming marvel called std::conditional
described here. In the same reference it says that a possible implementation is
template<bool B, class T, class F>
struct conditional { typedef T type; };
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };
So if in code I do something like
typename std::conditional<true,int,double>::type a;
the compiler will follow the first definition and if I do something like
typename std::conditional<false,int,double>::type b
the compiler will take the second. Why does that work ? What compilation rule is in place here ?
In short it has to do with template specialization rules. These are like function overloads but for types.
Here compiler prefers a more specialized type to the more general type.
template<bool B, class T, class F>
struct conditional { typedef T type; };
template<class T, class F>
struct conditional<false, T, F> { typedef F type; };
So if a template instantiation coditional<false, ...>
is seen by compiler it finds:
template<bool B, class T, class F> struct conditional
template<class T, class F> struct conditional<false, T, F>
At that point it tries to match as many specialized arguments as possible and ends up selecting the specialization with false
.
For example introducing another version like:
template<class F>
struct conditional<false, int, F> { typedef int type; };
and instantiating a template type like conditional<false, int, double>
will prefer specialization
template<class F> struct conditional<false, int, F>
to
template<class T, class F> struct conditional<false, T, F>
which is more general compared to the version with 2 specialized paramaters.
It is even OK to just declare the most generic case (i.e. generic form of the template is just declared but not defined) and only have specializations for cases you really intend to have. All non-specialized cases will result in compile errors and asking the user to specialize the case for a particular type.
Why does that work ? What compilation rule is in place here ?
I'm not an expert but I'll try to explain from the pratical point of view.
Hoping to use the rights terms...
With
template <bool B, class T, class F>
struct conditional { typedef T type; };
(but, with C++11, I prefer
template <bool B, typename T, typename>
struct conditional { using type = T; };
) you declare the template
template <bool, typename, typename>
struct conditional;
and define the generic (not specialized) version.
With
template< class T, class F>
struct conditional<false, T, F> { typedef F type; };
(or, in C++11,
template <typename T, typename F>
struct conditional<false, T, F> { using type = F; };
) you define a partial specialization of conditional
When the template arguments of a class (or struct) match two or more definitions, the compliler choose the more specialized one; so, for
typename std::conditional<false,int,double>::type
both definitions of the class match so the compiler choose the specialized one (the specialized with false
) anche type
is double
.
For
typename std::conditional<true,int,double>::type a;
only the generic version match, so type
is int
.
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