我有以下示例代码:
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);
}
基于重载决策规则,非模板版本应该是首选,因为基类的类型为Serializable
。但是,我希望SFINAE在模板版本中出现错误时会启动以实现重载解析(因为如果没有为类型定义&gt;&gt;运算符,则不应该考虑它。)
为什么即使不使用模板,它仍然会失败?
答案 0 :(得分:5)
基于重载决策规则,非模板版本应该是 首选,因为基类的类型为
Serializable
。
不完全。 [over.match.best]:
鉴于这些定义,可行函数
F1
被定义为a 如果适用于所有参数,则比另一个可行函数F2
具有更好的功能 i,ICSi(F1)不是比ICSi(F2)更差的转换序列,然后是
- 对于某些参数j,ICSj(F1)是比ICSj(F2)更好的转换序列,或者,如果不是,
- [...]
F1
不是功能模板专精,F2
是功能模板专业化[...]
这意味着只有当推断出功能模板的特化需要转换不比正常功能所需的转换更好时,才适用您的规则。
d
与Serializable&
的绑定比d与MyData&
(专业化参数的类型)的绑定更糟糕,[over.ics.ref] :
当引用类型的参数直接绑定(8.5.3)为a时 参数表达式,隐式转换序列是标识 转换,除非参数表达式的类型是a 派生类的参数类型,在这种情况下是隐式的 转换序列是派生到基础的转换(13.3.3.1)。
然而,我预计SFINAE会在出现错误时启动 模板版本在实例化为重载解析时 (因为如果没有为类型定义&gt;&gt;运算符,则不应该 被视为)。
SFINAE不适用于功能模板的内容。 [temp.deduct] / 8:
在直接上下文中只有无效的类型和表达式 函数类型及其模板参数类型可以导致a 扣除失败。
因此确实选择了函数模板的推导特化,并在实例化其定义时导致编译器错误。