Recently, I find that GCC
has changed the behavior during partial ordering, the concrete case is the following:
#include <iostream>
template<class T>
struct unknow_context{
using type = int;
};
template<class U>
void show(typename unknow_context<U>::type, U){ // candidate #1
std::cout<<"#1\n";
}
template<class T>
void show(int, T){ // candidate #2
std::cout<<"#2\n";
}
int main(){
show(0,0);
}
The result is, Clang prints #2
(any version of Clang
has printed a consistent result). However, GCC
has different behavior. The older version of GCC prints #2
, instead, the latest GCC complains the candidate functions are ambiguous. Let's see what the standard says about partial ordering.
temp.deduct.partial#2
The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.
So, we can get two sets of P/A pair for the candidate #1
and #2
, respectively. One is the transformed #1
as A, the original #2
as P. The other is the original #1
as P, the transformed #2
as A. So the two sets will be given as the following:
#a
|--------|------------------------------------------|
| P (#2) | A (#1) |
|--------|------------------------------------------|
| int | typename unknow_context<UniqueA>::type |
|--------|------------------------------------------|
| T | UniqueB |
|--------|------------------------------------------|
T
can be deduced from UniqueB
. For the first set, the rule says:
If a particular P contains no template-parameters that participate in template argument deduction, that P is not used to determine the ordering.
So, we put them aside first and consider them later.
#b
|----------------------------------|-------|
|P (#1) |A (#2) |
|----------------------------------|-------|
| typename unknow_context<U>::type |int |
|----------------------------------|-------|
| U |UniqueA|
|----------------------------------|-------|
For a non-deduced context, its value can be obtained from elsewhere.
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. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
So, we can ignore the pair typename unknow_context<U>::type
/ int
, and consider U
/ UniqueA
. U
can be deduced from UniqueA
.
If deduction succeeds for a given type, the type from the argument template is considered to be at least as specialized as the type from the parameter template.
From #b
, we get the result that #2
is at least as specialized as #1
.
The question is in the #a set
. The second pair has no problem, we can say that the second part of #1
is at least as specialized as the second part of #2
.
However, the rule for whether a function template F is more specialized than function template G is defined as:
Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering, the type from F is at least as specialized as the type from G. F is more specialized than G if F is at least as specialized as G and G is not at least as specialized as F.
So, we take attention to pair int / typename unknow_context<UniqueA>::type
, although the rule says "P is not used to determine the ordering". However, an important note in the standard says:
[ Note: Under [temp.deduct.call] and [temp.deduct.partial], if P contains no template-parameters that appear in deduced contexts, no deduction is done, so P and A need not have the same form. — end note ]
So, as far as now, from the P/A set #a
, #1
is still at least as specialized as #2
(deduction success). So, I think the latest GCC
should be correct (ambiguous, neither is more specialized than the other).
Question 1:
which compiler is correct?
Question 2:
whether the instantiation of specialization be performed during partial ordering? The standard seems to not specify whether the instantiation will be performed.
#include <iostream>
template<class T>
struct unknow_context{
using type = T;
};
template<class U>
void show(typename unknow_context<U>::type, U){
std::cout<<"#1\n";
}
template<class T>
void show(T, T){
std::cout<<"#2\n";
}
int main(){
show(0,0);
}
All chose #2
.
I'm concerned about the particular P/A pair
thereof, that is:
|----|------------------------------------------------------------|
|P |A |
|----|------------------------------------------------------------|
|T |typename unknow_context<UniqueA>::type /*Is it equivalent to|
| | UniqueA? */ |
|----|------------------------------------------------------------|
|T |UniqueA |
|----|------------------------------------------------------------|
whether typename unknow_context<UniqueA>::type
will be calculated to UniqueA
? It seems that All compiler treat typename unknow_context<UniqueA>::type
as a unique type rather than calculate it to UniqueA
.