15
4

2 回答 2

10

delete在检查它是否为d之前选择它要使用的函数。在复制构造函数可用且移动构造函数为deleted 的情况下,移动构造函数仍然是两者中的最佳选择。然后它看到它是deleted 并给你一个错误。

如果您有相同的示例,但实际上删除了移动构造函数,而不是将其delete设为 d,您会看到它编译得很好并且确实回退到使用复制构造函数:

#include <iostream>
#include <memory>
using namespace std;

struct A {
    unique_ptr<int> ref;
    A(const A&a) 
        : ref( a.ref.get() ? new int(*a.ref) : nullptr )
    {  }
    A(const int i) : ref(new int(i)) { }
    ~A() = default;
};

int main()
{
    A a[2] = { 0, 1 };
   return 0;
}

此类根本没有为它声明移动构造函数(甚至没有隐式声明),因此无法选择它。

于 2014-07-11T09:07:58.267 回答
10

没有“后备”。它被称为重载决议。如果重载决议中有多个可能的候选者,则根据一组复杂的规则选择最佳匹配,您可以通过阅读 C++ 标准或其草案找到这些规则。

这是一个没有构造函数的例子。

class X { };

void func(X &&) { cout << "move\n"; }            // 1
void func(X const &)  { cout << "copy\n"; }      // 2

int main()
{
    func( X{} );
}
  • 原样:打印“移动”
  • 注释掉“1”:打印“copy”
  • 注释掉“2”:打印“move”
  • 注释掉“1”和“2”:编译失败

在重载决议中,将右值绑定到右值比左值到右值具有更高的优先级。


这是一个非常相似的例子:

void func(int) { cout << "int\n"; }      // 1
void func(long) { cout << "long\n"; }    // 2

int main()
{
     func(1);
}
  • 原样:打印“int”
  • 注释掉“1”:打印“long”
  • 注释掉“2”:打印“int”
  • 注释掉“1”和“2”:编译失败

在重载解析中,精确匹配优于转换。


在您在此线程上的三个示例中,我们有:

1:两个候选函数;rvalue 更喜欢 rvalue(如我的第一个示例)

A(const A&);
A(A&&);           // chosen

2:两个候选函数;rvalue 更喜欢 rvalue(如我的第一个示例)

A(const A&); 
A(A&&);           // chosen

3:一个候选函数;没有比赛

A(const A&);      // implicitly declared, chosen

如前所述在案例 3 中没有 A(A&&) 的隐式声明,因为您有一个析构函数。

对于重载决议,函数体是否存在并不重要,重要的是函数是否被声明(显式或隐式)。

于 2014-07-11T22:38:22.950 回答