在下面的代码中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);
}
我对这种省略的正确性提出质疑,理由如下:
- 这种情况在第 8.5/16 节 (N3337) 的第一个子要点中有所涉及,它没有提及省略。
如果初始化是直接初始化,或者如果是复制初始化,其中源类型的 cv 非限定版本与目标类相同或派生类,则考虑构造函数。枚举了适用的构造函数(13.3.1.3),并通过重载决议(13.3)选择最佳构造函数。调用如此选择的构造函数来初始化对象,使用初始化表达式或表达式列表作为其参数。如果没有构造函数适用,或者重载决议不明确,则初始化格式错误。
- 请注意,下一个子要点明确提到了省略的可能性。
- 对移动构造函数的调用是显式的。怎么可以省略呢?