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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With