3

我有以下示例代码:

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);
}

现场样品

基于重载决议规则,非模板版本应该是首选,因为基类是 type Serializable。但是,我希望 SFINAE 在模板版本中在为重载解析实例化时出现错误时启动(因为如果没有为类型定义 >> 运算符,则不应考虑它)。

为什么即使模板不会被使用它仍然失败?

4

1 回答 1

5

基于重载决议规则,非模板版本应该是首选,因为基类是 type Serializable

不完全的。[over.match.best]:

鉴于这些定义,如果对于所有参数 i,ICSi(F1) 不是比 ICSi(F2) 更差的转换序列,则可行函数F1被定义为比另一个可行函数更好的函数F2,然后

  • 对于某些参数 j,ICSj(F1) 是比 ICSj(F2) 更好的转换序列,或者,如果不是,
  • […]
  • F1不是函数模板特化,F2而是函数模板特化 […]

这意味着只有当函数模板的推导特化需要进行不比普通函数需要的转换更好的转换时,您的规则才适用。并且 to 的绑定dSerializable&比 d to 的绑定更糟糕的转换MyData&(这是特化的参数的类型),[over.ics.ref]:

当引用类型的参数直接(8.5.3)绑定到参数表达式时,隐式转换序列是恒等转换,除非参数表达式的类型是参数类型的派生类,在这种情况下,隐式转换序列是派生到基础的转换 (13.3.3.1)。

但是,我希望 SFINAE 在模板版本中在为重载解析实例化时出现错误时启动(因为如果没有为类型定义 >> 运算符,则不应考虑它)。

SFINAE 不适用于函数模板的内容。[温度扣除]/8:

只有在函数类型及其模板参数类型的直接上下文中的无效类型和表达式会导致推导失败。

因此,确实选择了函数模板的推导特化,并在实例化其定义时导致编译器错误。

于 2014-12-04T18:35:46.217 回答