【发布时间】:2015-01-30 17:11:08
【问题描述】:
在下面的代码中,S 类的对象s 用于通过直接初始化D d(s); 来初始化D 类的对象。转换函数 S::operator D() 用于将对象s 转换为D 类型的临时对象。然后,gcc 和 clang 都省略了对移动构造函数D(&&) 的显式调用,将这个临时对象移动到d。见live example。
#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);
}
我对这种省略的正确性提出异议,理由如下:
- 第 8.5/16 节 (N3337) 中的第一个子项目符号对此案例进行了介绍,其中没有提及省略。
如果初始化是直接初始化,或者如果是 复制初始化,其中源的 cv 不合格版本 type 与该类的类相同或派生类 目的地,构造函数被考虑。适用的构造函数 枚举(13.3.1.3),通过重载选择最好的 决议(13.3)。调用如此选择的构造函数进行初始化 对象,以初始化表达式或表达式列表作为其 论点。如果没有构造函数适用,或者重载决议是 模棱两可,初始化格式不正确。
- 请注意,下一个子要点明确提到了省略的可能性。
- 对移动构造函数的调用是显式的。怎么能去掉?
【问题讨论】:
标签: c++ c++11 initialization language-lawyer copy-elision