问题
Given the following program
#include <iostream>
template<class T> struct id { using type = T; };
template<class T1, class T2>
int func(T1, T2) { return 0; }
template<class T1, class T2>
int func(typename id<T1>::type, typename id<T2>::type) { return 1; }
int main()
{
std::cout << func<int, int>(0, 0) << std::endl;
}
GCC and Clang both prints 1
for this program. Is this program guaranteed to print 1
by the standard?
I tried finding the answer here but couldn't decipher it. It looks like the function templates might be equivalent and therefore breaks ODR but I'm not sure.
Does changing the second function template to
template<class T>
using id_type = typename id<T>::type;
template<class T1, class T2>
int func(id_type<T1>, id_type<T2>) { return 1; }
make a difference?
回答1:
This is bog-standard partial ordering. We substitute unique types into one of the function templates and try to deduce the other against it. Do it both ways and if deduction only succeeds in one direction, we have an order. If you want to read the arcane rules, see [temp.func.order] and [temp.deduct.partial].
So here,
- Substituting
T1=U1, T2=U2
into the first overload's function type producesint f(U1, U2);
Can we deduceT1
andT2
in the second overload from this? No; both are in non-deduced contexts. Ergo, deduction fails. - Substituting
T1=U1, T2=U2
into the second overload producesint f(id<U1>::type, id<U2>::type)
(this is conducted in the definition context so we can't substitute further intoid
- there may be a specialization somewhere). Can we deduce theT1
andT2
in the first overload from this? Yes, by deducingT1 = id<U1>::type
andT2 = id<U2>::type
. Deduction succeeds.
Since deduction succeeds only in one direction - deducing the first from transformed second - the second is more specialized than the first and is preferentially picked by overload resolution.
The alias template case changes nothing.
These templates are neither equivalent nor functionally equivalent.
回答2:
The following func
overload
// Denote as overload F. template<class T1, class T2> int func(typename id<T1>::type, typename id<T2>::type) { return 1; }
is more specialized than the following func
overload
// Denote as overload G. template<class T1, class T2> int func(T1, T2) { return 0; }
thus, the former is chosen by overload resolution.
(All ISO Standard references below refer to N4659: March 2017 post-Kona working draft/C++17 DIS)
The partial ordering of the G
and F
overloads of func
is governed by:
- [temp.func.order]/2, [temp.func.order]/3 and [temp.func.order]/4, and
- [temp.deduct.partial]/2 and [temp.deduct.partial]/10.
来源:https://stackoverflow.com/questions/62409234/function-template-overload-resolution-dependent-and-non-dependent-parameters