While reading another question, i came to a problem with partial ordering, which i cut down to the following test-case
template<typename T>
struct Const { typedef void type; };
template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1
template<typename T>
void f(T, void*) { cout << "void*"; } // T2
int main() {
// GCC chokes on f(0, 0) (not being able to match against T1)
void *p = 0;
f(0, p);
}
For both function templates, the function type of the specialization that enters overload resolution is void(int, void*)
. But partial ordering (according to comeau and GCC) now says that the second template is more specialized. But why?
Let me go through partial ordering and show where i have questions. May Q
be an unique made-up type used for determining partial ordering according to 14.5.5.2
.
- Transformed parameter-list for
T1
(Q inserted):(Q, typename Const<Q>::type*)
. The types of the arguments areAT
=(Q, void*)
- Transformed parameter-list for
T2
(Q inserted):BT
=(Q, void*)
, which are also the types of the arguments. - Non-transformed parameter-list for
T1
:(T, typename Const<T>::type*)
- Non-transformed parameter-list for
T2
:(T, void*)
Since C++03 under-specifies this, i did use the intention that i read about in several defect reports. The above transformed parameter list for T1
(called AT
by me) is used as argument list for 14.8.2.1
"Deducing template arguments from a function call".
14.8.2.1
does not need to transform AT
or BT
itself anymore (like, removing reference declarators, etc), and goes straight to 14.8.2.4
, which independently for each A
/ P
pair does type deduction:
AT
againstT2
:{
(Q, T)
,
(void*, void*)
}
.T
is the only template parameter here, and it will find thatT
must beQ
. Type deduction succeeds trivially forAT
againstT2
.BT
againstT1
:{
(Q, T)
,
(void*, typename Const<T>::type*)
}
. It will find thatT
isQ
, too here.typename Const<T>::type*
is an un-deduced context, and so it won't be used to deduce anything.
Here is my first question: Will this now use the value of T
deduced for the first parameter? If the answer is no, then the first template is more specialized. This can't be the case, because both GCC and Comeau say that the second template is more specialized, and i don't believe they are wrong. So we assume "yes", and insert void*
into T
. The paragraph (14.8.2.4
) says "Deduction is done independently for each pair and the results are then combined" and also "In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified." This sounds like "yes" too.
Deduction therefore succeeds too, for every A / P pair. Now, each template is at least as specialized as the other, because deduction didn't also rely on any implicit conversions and succeeded in both directions. As a result, the call should be ambiguous.
So my second question: Now, why do the implementations say that the second template is more specialized? What point did i overlook?
Edit: I tested explicit specialization and instantiation, and both, in recent GCC versions (4.4
) tell me that the reference to the specialization is ambiguous, while an older version of GCC (4.1
) doesn't rise that ambiguity error. This suggests that recent GCC versions have inconsistent partial ordering for function templates.
template<typename T>
struct Const { typedef void type; };
template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1
template<typename T>
void f(T, void*) { cout << "void*"; } // T2
template<> void f(int, void*) { }
// main.cpp:11: error: ambiguous template specialization
// 'f<>' for 'void f(int, void*)'
See Question&Answers more detail:os