10

尝试编译以下代码:

struct Foo
{
    explicit Foo ( void ) { }
    explicit Foo ( Foo&& rhs ) { }
};

Foo bar ( void )
{
    return Foo();
}

收到以下错误:

调用 'Foo' 的隐式删除的复制构造函数

好吧,很明显 copy-ctor 被隐式​​删除了。

问题1:为什么编译器需要copy-ctor Foo?我期望 的返回值是用 move-ctor 从右bar值构造的。Foo()

然后我将 move-ctor 重新声明为隐式,一切都成功编译。

问题 2:为什么当我将 move-ctor 重新声明为隐式时,编译器不再需要 copy-ctor?

问题 3:关键字在复制和移动 ctor 的上下文中意味着什么explicit,因为它肯定意味着与常规 ctor 的上下文不同的东西。

4

3 回答 3

10

这是因为返回值被认为是隐式转换

引用 C++11 标准:

6.6.3 返回语句

2 [...]

带有非 void 类型表达式的 return 语句只能用于返回值的函数;表达式的值返回给函数的调用者。表达式的值被隐式转换为它出现的函数的返回类型。return 语句可能涉及临时对象 (12.2) 的构造和复制或移动。[...]

从返回表达式到保存返回值的临时对象的转换是隐式的。所以就像这会导致错误一样

Foo f = Foo();   // Copy initialization, which means implicit conversion

将代码作为您的示例也会触发类似的代码。


问题1:为什么编译器需要Foo的copy-ctor?我希望 bar 的返回值是从带有 move-ctor 的右值 Foo() 构造的。

这是因为Foo(Foo&&)不是一个可行的过载,因为上面的原因。规则规定,每当无法使用移动构造函数时,编译器就会考虑复制构造函数,在您的情况下,由于存在用户定义的移动构造函数,复制构造函数会被隐式删除。

问题 2:为什么当我将 move-ctor 重新声明为隐式时,编译器不再需要 copy-ctor?

这是因为您的移动构造函数现在可以使用。因此,编译器可以立即使用它,甚至无需考虑复制构造函数的存在。

问题 3:explicit 关键字在复制和移动 ctor 的上下文中意味着什么,因为它绝对意味着与常规 ctor 的上下文不同的东西。

恕我直言,这没有意义,而且只会导致问题,就像您的情况一样。

于 2014-02-19T07:03:40.890 回答
6

的返回类型barFoo。没有复制构造函数,并且显式移动构造函数无法工作,因为仍然需要和之间的隐式转换。从这个意义上说,与任何其他转换构造函数没有什么不同。从不同类型的转换仍然会出现问题。这是一个类似的例子,使用:Foo&&Fooexplicit Foo(Foo&&)explicitint

struct Foo
{
    explicit Foo(int) {}
};

Foo bar ( void )
{
    return 42; // error: could not convert '42' from 'int' to 'Foo'
}

Q1:因为没有其他东西可以使用。

Q2:因为它使用移动构造函数来隐式转换 from Foo&&to Foo

Q3:这意味着与普通转换构造函数相同。

于 2014-02-19T07:02:33.567 回答
2

这与 C++ 中重载解析的工作方式有关。

重载决议的第一步是形成一组候选函数。第二步是将候选函数集缩小为一组可行函数。第三步是选择唯一的最佳可行函数,如果有的话。如果最好的可行函数被删除,那么程序是错误的。

因为声明了 move 构造函数explicit,所以它不是隐式转换为函数返回类型的候选函数。Foo()唯一的候选函数是Foo::Foo(const Foo&)隐式声明的复制构造函数。这是一个候选函数,即使它被声明为 deleted。它是通过重载决议选择的,是唯一可行的功能;然后你会因为尝试调用已删除的函数而出错。

如果不声明移动构造函数explicit,则移动构造函数和隐式声明的复制构造函数都是候选函数。在这种情况下,两者都将是可行的。但是,移动构造函数赢得了重载决议,因为右值更喜欢绑定到右值引用而不是 const 左值引用。因此移动构造函数是最好的可行函数。在这种情况下,复制构造函数被删除并不重要,因为它在重载决议中丢失了。

tl;博士:

答案 1:因为移动构造函数不是转换的候选函数

答案 2:因为移动构造函数是一个候选函数,并且赢得了重载决议。

答案 3:不,这意味着同样的事情。

于 2014-02-19T07:51:07.037 回答