【问题标题】:Does SFINAE apply to function bodies?SFINAE 是否适用于功能体?
【发布时间】:2014-12-04 18:17:57
【问题描述】:

我有以下示例代码:

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

(Live Sample)

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

为什么不使用模板还是失败?

【问题讨论】:

  • the non-template version should be preferred 仅在完全匹配的情况下。看看如果你使用 MyData 而不是 Serializable 会发生什么。

标签: c++ templates language-lawyer overload-resolution upcasting


【解决方案1】:

根据重载解析规则,非模板版本应该是 首选,因为基类的类型为 Serializable

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

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

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

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

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

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

SFINAE 不适用于函数模板的内容。 [temp.deduct]/8:

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

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

【讨论】:

  • 这里“专业化”一词的标准用法实际上是模板的“实例化”,对吗?因为在我看来,专业化是为类型显式实现一个函数。就我而言,我没有明确专门化基本功能模板。
  • @void.pointer 看来您混淆了术语。 specialization 是使用推导出的模板参数实例化的函数。你说的是明确的专业化
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-14
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 2012-06-16
相关资源
最近更新 更多