I am not clear about the interaction of default template arguments in the context of partial specialization, for choosing which is the better matching template. This questions stems from code posted in this answer by max66.
Given the definitions of the classes A
and B
:
template <int N> struct A { static const int code = N; };
struct B{};
and the following template classes:
// primary template
template <typename, typename Enable = bool_constant<true>>
struct cond : public bool_constant<false> {};
// specialization
template <typename T>
struct cond<T, bool_constant<(0 == T::code)>> : public bool_constant<true> {};
1) cond<B>::value
evaluates to false
(i.e. the primary is chosen). This is clear as the primary template yields cond<B, bool_constant<true>>
, the specialization fails, hence the primary template is the only possible choice.
2) cond<A<0>>::value
evaluates to true
(i.e. the specialization is chosen). This is clear as the primary template yields cond<B, bool_constant<true>>
, the specialization also yields cond<B, bool_constant<true>>
, hence the specialization is preferred because the argument for the 2nd template parameter is explicitly given.
3) cond<A<1>>::value
evaluates to false
(i.e. the primary is chosen). This is not clear to me. The primary template yields cond<B, bool_constant<true>>
, the specialization yields cond<B, bool_constant<false>>
. Given the argument for the 2nd template parameter is explicitly given in the specialization, why is not preferred?
I suppose the behaviour in (3) is due to some interaction between the default template argument of the primary template and the specialization. In this answer Jerry Coffin states something which might explain this behaviour:
if we change the specialization so that its specialization is for a type other than the default provided by the base template then the base template will be chosen.
Can somebody please elaborate on this rule? Thanks
is identical to
Later might be clearer to understand the result.
When you write
cond<C>
, thanks to default argument, it is equivalent tocond<C, bool_constant<true>>
.Then we try to match that to "better instantiation".
We have the choice between:
and partial specialization, which use SFINAE:
If
0 == T::code
is ill formed, specialization is discarded and only primary template is a viable solution, so it is used.Else if
0 == T::code
evaluates tofalse
, the specialization doesn't match and primary template is also used.Note that using
cond<C, bool_constant<false>>
would use the specialization in that case.Else,
0 == T::code
evaluates totrue
, and then both primary and specialization are viable, but specialization is more specialized, so it is chosen.