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?

+3


source to share


2 answers


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

.

+3


source


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.

+3


source







All Articles