是否允许使用复制/移动省略来制作使用删除功能的程序格式正确的文件? [英] Is copy/move elision allowed to make a program using deleted functions well-formed?

查看:107
本文介绍了是否允许使用复制/移动省略来制作使用删除功能的程序格式正确的文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#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 使用刚刚创建的临时对象作为参数的move构造函数使用 Thing 类的对象。而且我希望该程序被认为格式不正确,因为它包含已删除的move构造函数的调用,即使它可能被删除。标准的 class.copy.elision 部分似乎也要求这样做:

I expect Thing thing{Thing{}}; statement to mean construction of temporary object of Thing class using default constructor and construction of thing object of Thing class using move constructor with just created temporary object as an argument. And I expect that this program to be considered ill-formed because it contains an invocation of deleted move constructor, even though it can be potentially elided. The class.copy.elision section of standard seems to demand this as well:


所选的构造函数必须是即使通话被取消也可以访问

the selected constructor must be accessible even if the call is elided

通过简化的值类别来保证复制省略的措辞似乎也不允许。

但是gcc 7.2(还有clang 4,但不是VS2017,VS2017相对仍不支持保证的复制省略)将编译此代码就可以了取消移动构造函数调用。

However gcc 7.2 (and clang 4 as well, but not VS2017 which still does not support guaranteed copy elision) will compile this code just fine eliding move constructor call.

在这种情况下哪种行为是正确的?

Which behavior would be correct in this case?

推荐答案

它不会生成格式错误的程序。它完全摆脱了对已删除函数的引用。提案中的适当措辞如下:

It doesn't make an ill-formed program build. It gets rid of the reference to the deleted function entirely. The appropriate wording in the proposal is here:

[dcl.init]项目符号17.6

[dcl.init] bullet 17.6


如果初始值设定项表达式为prvalue,且源类型的cv不合格
版本与
目标的类别相同,则使用初始值设定项表达式初始化
目标对象。 [示例:T x = T(T(T()));调用T的默认
构造函数初始化x。 ]

If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object. [ Example: T x = T(T(T())); calls the T default constructor to initialize x. ]

该示例进一步增强了这一点。

The example further strengthens this. Since it indicates the whole expression must collapse into a single default construction.

要注意的是,当删除副本时,由于删除了删除的函数,因此永远不会使用它值类别,因此该程序不是引用它。

The thing to note is that the deleted function is never odr-used when the copies are elided due to value categories, so the program is not referring to it.

这是一个重要的区别,因为 other 复制省略的形式仍然会使用odr,如此处所述:

This is an important distinction, since the other form of copy elision still odr-uses the copy c'tor, as described here:

[basic.def.odr] / 3

[basic.def.odr]/3


...选择复制或移动类类型的对象的构造函数是
odd-使用的,即使该调用实际上被实现$ b $取消。 b([class.copy] ...

... A constructor selected to copy or move an object of class type is odr-used even if the call is actually elided by the implementation ([class.copy] ...

[class.copy]描述了另一种形式的允许(但不是强制性)复制-elision。如果我们与您的班级一起演示,则为:

[class.copy] describes the other form of permissible (but not mandatory) copy-elision. Which, if we demonstrate with your class:

Thing foo() {
    Thing t;
    return t; // Can be elided according to [class.copy.elision] still odr-used
}

应该使程序格式错误。 海湾合作委员会如预期那样抱怨

Should make the program ill-formed. And GCC complains about it as expected.

顺便说一句。如果您认为在线编译器中的上一个示例是魔术师的把戏,那么GCC会抱怨,因为它需要调用看看提供定义时会发生什么情况。

And by the way. If you think the previous example in the online compiler is a magicians trick, and GCC complains because it needs to call the move c'tor. Have a look at what happens when we supply a definition.

这篇关于是否允许使用复制/移动省略来制作使用删除功能的程序格式正确的文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆