简体   繁体   中英

(partial) template specialization for bool

I'm struggling to understand how template specialization for bool works for this slide taken from cppcon 2017

Short question: why (first) primary template handles odd N cases when its signature is

<..., bool = (N % 2 == 0) > ?

Trying to understand myself I simplified down to

#include<iostream>
template<unsigned N, bool =(N%2==0)> struct S { void operator()(){ std::cout << "A\n"; } };
template<unsigned N> struct S<N, true> { void operator()(){ std::cout << "B\n"; } };
int main()
{
    S<2>{}();
    S<3>{}();
}

which prints B A , showings same (yet mysterious to me) behavior as linked talk, but if I change template specialization to

template<unsigned N> struct S<N, false> { void operator()(){ std::cout << "B\n"; } };
                                 -----

it prints A B : how compiler chooses between primary S and its specialization?

The compiler always prefers the specialization over the generalization and thus will always pick it if it can.

The struct S has a partial template specialization that will only be picked if the second template parameter evaluates to true , so let's see how that works:

S<2>{}();

Here the template parameter N is 2 and so 2 % 2 == 0 holds true. Which means the specialization will be picked over the generalized S because the specialization requires the second parameter to be true and B is printed.

This isn't the case for S<3>{}(); because 3 % 2 == 0 holds false, and thus the generalized case is used, giving you A .

If you swap it around and make the specialization only accept false for N % 2 == 0 then the results will be the exact opposite, 2 % 2 == 0 still holds true but the specialization only accepts false so it's not picked, 3 % 2 == 0 holds false and thus it will be picked, resulting in AB .

It's specialization; the compiler choose the most specialized version available.

Ignore for a moment the default value for bool (that transform S<2> in S<2, true> and S<3> in S<3, false> ); you have

template <unsigned N, bool>
struct S
 { /* something */};

template <unsigned N>
struct S<N, true>
 { /* something */};

The first one is neutral regarding the second (the bool one) template parameter; so matches both S<2, true> and S<3, false> .

The second one require that the second template parameter is true , so matches only S<2, true> . And is more specialized than the first one because every match for the second template is also a match for the first one but there are matches for the first one that aren't matches for the second one ( S<3, false> , by example).

For S<3, false> the compiler find only a template that matches (the first one) so choose the first one.

For S<2, true> the compiler find both templates that match and coose (rule of C++) the most specialized, that is the second one.

When you change the true in false you have that S<3, false> matches both version, so the second one is choosed, and S<2, true> matches only the first one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM