Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Partial specialization of variadic templates

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.

like image 826
iorate Avatar asked Dec 06 '11 17:12

iorate


1 Answers

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.

like image 92
Mikhail Semenov Avatar answered Sep 19 '22 05:09

Mikhail Semenov