考虑以下代码:
#include <iostream>
struct Thing
{
Thing(void) {std::cout << __PRETTY_FUNCTION__ << std::endl;}
Thing(Thing const &) = delete;
Thing(Thing &&) = delete;
Thing & operator =(Thing const &) = delete;
Thing & operator =(Thing &&) = delete;
};
int main()
{
Thing thing{Thing{}};
}
我预计Thing thing{Thing{}};
声明表示临时对象的构造Thing
使用默认构造函数和构造的类thing
的对象Thing
使用移动构造函数并以刚刚创建的临时对象作为参数的类。我预计该程序会被视为格式错误,因为它包含对已删除移动构造函数的调用,即使它可能会被忽略。这类.复制.省略标准部分似乎也要求这一点:
即使调用被省略,所选的构造函数也必须可访问
The 通过简化的值类别保证复制省略的措辞似乎也不允许。
然而 gcc 7.2 (还有 clang 4,但不是 VS2017仍然不支持保证复制省略) will 编译这段代码就好了省略移动构造函数调用。
在这种情况下哪种行为是正确的?
它不会构建格式错误的程序。它完全摆脱了对已删除函数的引用。提案中的适当措辞如下:
[dcl.init] 项目符号 17.6
如果初始值设定项表达式是纯右值且 cv 未限定
源类型的版本与源类型的类是同一类
目的地,初始化表达式用于初始化
目标对象。 [ 示例:T x = T(T(T()));调用 T 默认值
构造函数来初始化 x。 ]
这个例子进一步强化了这一点。因为它表明整个表达式必须折叠成单个默认结构。
需要注意的是,当由于值类别而删除副本时,删除的函数永远不会被 ODR 使用,因此该程序是not指的是它。
这是一个重要的区别,因为other复制省略的形式仍然是 odr-使用复制 c'tor,如下所述:
[基本.def.odr]/3
...选择用于复制或移动类类型对象的构造函数是
odr-使用,即使该调用实际上被实现省略了
([类.副本] ...
[class.copy] 描述了允许的(但不是强制的)复制省略的其他形式。如果我们在课堂上演示一下:
Thing foo() {
Thing t;
return t; // Can be elided according to [class.copy.elision] still odr-used
}
应该使程序格式错误。正如预期的那样,GCC 对此有所抱怨.
顺便说一下。如果您认为在线编译器中的前面的示例是魔术师的把戏,并且 GCC 会抱怨,因为它需要call移动c'tor。看看当我们提供定义时会发生什么.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)