Role of default template arguments in the context

2019-03-04 12:33发布

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

1条回答
虎瘦雄心在
2楼-- · 2019-03-04 13:15
template <typename, typename Enable = bool_constant<true>>
struct cond : public bool_constant<false> {};

is identical to

template <typename, typename Enable = bool_constant<true>> struct cond;

template <typename, typename Enable>
struct cond : public bool_constant<false> {};

Later might be clearer to understand the result.

When you write cond<C>, thanks to default argument, it is equivalent to cond<C, bool_constant<true>>.

Then we try to match that to "better instantiation".

We have the choice between:

// primary template
template <typename, typename Enable>
struct cond : public bool_constant<false> {};

and partial specialization, which use SFINAE:

// specialization
template <typename T>
struct cond<T, bool_constant<(0 == T::code)>> : public bool_constant<true> {};

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 to false, 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 to true, and then both primary and specialization are viable, but specialization is more specialized, so it is chosen.

查看更多
登录 后发表回答