This is an error in MSVC, the program is correct.
How to test(a, b) choose #1 ?
For test(a, b) , overload resolution performs the output of the argument from the function call (see [temp.deduct.call] ):
- # 1 is output as
void test(A<int>, A<int>) - # 2 is output as
void test(A<int>, <non-deduced context>) , arg2 is then synthesized from arg1 as A<int> , the result is: void test(A<int>, A<int>)
There is more than one viable alternative, so the process continues with partial ordering (see [temp.deduct.partial] ).
Partial ordering uses the original templates, trying to subtract from the type ( [temp.deduct.type] ) a pair from each argument of one template to another (after a slight conversion) and vice versa. If the deduction succeeds in only one direction, the winning template is selected as the most specialized.
Type inference is not always performed in nested contexts (anything to the left of the scope :: operator is a nested context), see [temp. deduct.type] / 5 :
Impossible contexts:
- nested-name-specifier of the type that was specified using qualified-id .
.,.
So, this means that # 2 will always lose in partial order; the output to it will always fail, while the other path will always be successful:
Output of void test(A<T>,A<T>) from void test(A<U>, typename identity<A<U>>::type) : P1 = A<T> , A1 = A<U> , P2 = A<U> , A2 = A<U> , success, T = U
The output of void test(A<T>, typename identity<A<T>>::type) from void test(A<U>,A<U>) : P1 = A<T> , A1 = A<U> , P2 = <non-deduced-context> , fail
So, the result of partial ordering is to use void test(A<T>,A<T>) (# 1) to call test(a, b) .
How to test(b, c) choose #2 ?
For test(b, c) , A<X> cannot be inferred from C (implicit conversions are not taken into account when subtracting), so # 2 is the only viable alternative. identity_t<A<X>> allowed after deduction to A<int> , since X known (derived from the first argument).
Why doesn't the compiler complain about two test instances with the same signature?
The template parameters specified in the function declaration are part of the signature of the created function. See [temp.over.link] :