44
votes

Consider the following class template 'X' and its partial specializations.

template <class ...Types>
struct X {};               // #1

template <class T1>
struct X<T1> {};           // #2

template <class T1, class ...Types>
struct X<T1, Types...> {}; // #3

X<int> x;                  // #2 or #3 ?

I suspect X<int> is ambiguous. It is because:

It is obvious that both #2 and #3 are more specialized than #1, #2 and #3 are now compared. According to 14.5.5.2, let's consider which of the following #2' and #3' is more specialized.

template <class T1>
void f(X<T1>);             // #2'

template <class T1, class ...Types>
void f(X<T1, Types...>);   // #3'

According to 14.8.2.4, the first step is the template argument deduction using #2' as the argument template and #3' as the parameter template. Given the only argument type is X<A1>, the deduced T1 is A1, and Types is empty.

A = X<A1>, P = X<T1, Types...>  =>  T1 = A1, Types = {}

The second step is done using #3' as the argument template and #2' as the parameter template. Given the only argument type is X<A1, Args...>, according to 14.8.2.5/9 (note that this paragraph is recently revised by N3281), Args is simply ignored, the deduced T1 is A1 and argument deduction succeeds.

A = X<A1, Args...>, P = X<T1>  =>  T1 = A1 (Args is ignored)

Finally, the bidirectional argument deductions succeeded. So #2 is just as specialized as #3. In conclusion, X<int> is ambiguous.

My question is: "is my interpretation correct?"

If this interpretation is correct, the definition of 'std::common_type' in 20.9.7.6/3 is inappropriate.

template <class ...T>
struct common_type;            // #1

template <class T>
struct common_type<T>          // #2
{
    typedef T type;
};

template <class T, class U>
struct common_type<T, U>       // #3
{
    typedef
        decltype(true ? declval<T>() : declval<U>())
    type;
};

template <class T, class U, class ...V>
struct common_type<T, U, V...> // #4
{
    typedef typename
        common_type<typename common_type<T, U>::type, V...>::type
    type;
};

When common_type<A, B> is used, #3 and #4 are ambiguous.

Note: on the first example, GCC 4.7.0 (snapshot) and Clang 3.0 select #2. However, these compilers are so unreliable that they don't follow the other changes by N3281.

1
It looks like you are correct. An empty parameter pack should not affect partial ordering. gcc seems to ignore this and place a variadic template lower in the list, other things being equal. E.g. it compiles an example at 14.5.6.2/5 which is explicitly stated to be ambiguous.n. 1.8e9-where's-my-share m.
Correctness is usually the subject of unit tests, especially in programming. This ensures that your interpretation is correct and that you understand the language specifications to a high degree of confidence, both of which may be in question here.djhaskin987
@n.m. Is this code what you are talking about? I've taken that code from N3242, as linked from WikipediaAaron McDaid
14.5.6.2/5 (from N3242) "The presence of unused ellipsis and default arguments has no effect on the partial ordering of function templates" (my emphasis). Maybe this only applies to function templates, while this question is about class templates?Aaron McDaid
@Aaron: no, this one. This is the last example of 14.5.6.2. It compiles though the comment plainly states it should not.n. 1.8e9-where's-my-share m.

1 Answers

8
votes

14.8.2.4, section 11 (I refer to draft N3242).

In most cases, all template parameters must have values in order for deduction to succeed, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. [ Note: A template parameter used in a non-deduced context is considered used. —end note ] [ Example:

template <class T> T f(int); // #1
template <class T, class U> T f(U); // #2
void g() {
f<int>(1); // calls #1
}

In your case, #3 will be used.