I have the following sample code:
class Serializable {};
class MyData : public Serializable {};
void GetData( Serializable& ) {}
template<typename T>
void GetData( T& data )
{
std::istringstream s{"test"};
s >> data;
}
int main()
{
MyData d;
GetData(d);
}
Based on overload resolution rules, the non-template version should be preferred because the base class is of type Serializable
. However, I expect SFINAE to kick in when there are errors in the template version when it is instantiated for overload resolution (because if the >> operator is not defined for a type, it should not be considered).
Why is it still failing even though the template won't be used?
Based on overload resolution rules, the non-template version should be preferred because the base class is of type
Serializable
.
Not quite. [over.match.best]:
Given these definitions, a viable function
F1
is defined to be a better function than another viable functionF2
if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
- for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
- […]
F1
is not a function template specialization andF2
is a function template specialization […]
That means that only if the deduced specialization of the function template necessitates a conversion that isn't better than the conversion that the normal function necessitates, your rule applies.
And the binding of d
to Serializable&
is a worse conversion than the binding of d to MyData&
(which is the type of the parameter of the specialization), [over.ics.ref]:
When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion (13.3.3.1).
However, I expect SFINAE to kick in when there are errors in the template version when it is instantiated for overload resolution (because if the >> operator is not defined for a type, it should not be considered).
SFINAE doesn't apply for the content of a function template. [temp.deduct]/8:
Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure.
Hence the deduced specialization of the function template is indeed chosen, and causes a compiler error while instantiating its definition.
来源:https://stackoverflow.com/questions/27301135/does-sfinae-apply-to-function-bodies