How std :: conditional works
We have this little metaprogramming miracle called std::conditional
, described here . The same link 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 execute the first definition and if I do something like
typename std::conditional<false,int,double>::type b
the compiler will take the second one. Why does it work? What's the compilation rule here?
source to share
Why does it work? What's the compilation rule here?
I am not an expert, but I will try to explain from a theoretical point of view.
In hopes of exploiting the terms of rights ...
FROM
template <bool B, class T, class F>
struct conditional { typedef T type; };
(but, as of C ++ 11, I prefer
template <bool B, typename T, typename>
struct conditional { using type = T; };
) you declare a template
template <bool, typename, typename>
struct conditional;
and define a generic (non-specialized) version.
FROM
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 conditional
When the arguments of a class (or structure) template match two or more definitions, the compiler chooses the more specialized one; so for
typename std::conditional<false,int,double>::type
both class definitions are the same, so the compiler chooses the specialized (specialized with false
) anche type
is double
.
For
typename std::conditional<true,int,double>::type a;
only the generic version matches, therefore type
- int
.
source to share
In short, it has to do with the template specialization rules. They are similar to functional overloads, but for types.
Here the compiler prefers a more specialized type over a 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 instance is coditional<false, ...>
considered by the compiler, it finds:
- general template
template<bool B, class T, class F> struct conditional
- all his specializations:
template<class T, class F> struct conditional<false, T, F>
At this point, he tries to match as many specialized arguments as possible and ends up choosing a specialization with false
.
For example, enter a different version, for example:
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 than the version with two specialized parameters.
Some tricks at this point:
It's even okay to just declare the most general case (i.e. the generic form of the template is only declared but not defined) and only has specializations for the cases you really intend to have. All non-specialized cases will result in compilation errors and ask the user to specialize the case for a specific type.
source to share