SFINAE不适用于自动生成的特殊成员函数

SFINAE is not applied to auto generated special member function?

本文关键字:成员 函数 不适用 适用于 自动生成 SFINAE      更新时间:2023-10-16
class Myclass{
private:
    int i;
public:
    Myclass(){}
    Myclass(const Myclass &lvalue){} //<---
    template<typename T>Myclass(T& lvalue):i(lvalue){}
};
int main()
{
    Myclass a;
    Myclass b(a);
    return 0;
}

上面的代码编译失败:

error: cannot convert ‘Myclass’ to ‘int’ in initialization

这是一个错误吗?我已经使用 g++ 5.3 和 clang3.9 对其进行了测试

不,不是错误。这与SFINAE无关。

让我们对以下内容进行重载解析:

Myclass b(a);

我们有两个可行的重载:

 Myclass(Myclass const&); // your copy ctor
 Myclass(Myclass& );      // your ctor template, with [T=Myclass]

两者都是完全匹配的。选择最佳可行候选人的决胜因素之一是选择最不符合 cv 条件的参考 - 在本例中为模板。这最终会尝试使用 Myclass 初始化您的int,因此出现错误。(请注意,有一个决胜局更喜欢非模板而不是模板 - 但它的排名低于参考文献上的简历资格)。

在这种情况下,解决方案是引入 SFINAE 以禁用此构造函数,以防它应该使用复制 ctor。那是:

template <class T, class = std::enable_if_t<!std::is_convertible<T*, Myclass const*>::value>>
Myclass(T& );

现在这个构造函数对于Myclass b(a)来说是不可行的.

其他答案很好,但我想我会添加标准引用来补充。最新草案"对隐式转换序列进行排名"部分指出:

  • 标准转化序列 S1 是比标准转化序列更好的转化序列S2

    • S1S2 是引用绑定 ([dcl.init.ref]),引用引用的类型是相同的类型,但顶级除外 CV 限定符,以及引用初始化为的类型 S2 引用比引用的类型更符合 CV 标准 由S1引用初始化。[ 示例:

      int f(const int &);
      int f(int &);
      int g(const int &);
      int g(int);
      int i;
      int j = f(i);                   // calls f(int &)