6

在下面的代码中s,类对象S用于使用D直接初始化来初始化类对象D d(s);。转换函数 S::operator D() 用于将对象s转换为 类型的临时对象D。然后,gcc 和 clang 都省略了对 move 构造函数的显式调用D(&&),将这个临时对象移动到d. 见活的例子

#include <iostream>
struct D;
struct S{ operator D(); };

struct D{
    D(){}
    D(D&&) { std::cout << "move constructor" << '\n'; }
};

S::operator D() { std::cout << "conversion function" << '\n'; return D(); }

int main()
{
    S s;
    D d(s);
}

我对这种省略的正确性提出质疑,理由如下:

  1. 这种情况在第 8.5/16 节 (N3337) 的第一个子要点中有所涉及,它没有提及省略。

    如果初始化是直接初始化,或者如果是复制初始化,其中源类型的 cv 非限定版本与目标类相同或派生类,则考虑构造函数。枚举了适用的构造函数(13.3.1.3),并通过重载决议(13.3)选择最佳构造函数。调用如此选择的构造函数来初始化对象,使用初始化表达式或表达式列表作为其参数。如果没有构造函数适用,或者重载决议不明确,则初始化格式错误。

  2. 请注意,下一个子要点明确提到了省略的可能性。
  3. 对移动构造函数的调用是显式的。怎么可以省略呢?
4

1 回答 1

8

C++ 标准喜欢为在一个完全不同的地方定义的规则创建例外。

复制/移动省略规则在 12.8/31 中指定。您的代码中有两个复制/移动操作要消除。

第一个很简单:在 内operator D,将返回表达式中构造的临时值移动到表示函数返回值的临时值。Bullet 3 允许省略这一举动。

第二个是临时函数返回值向d对象的移动。同样,项目符号 3 允许省略。

  • 当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动
于 2014-12-02T12:51:49.737 回答