有了保证的复制省略,为什么需要完全定义类?

Sto*_*ica 22 c++ language-lawyer c++17

这篇文章的后续内容.考虑以下:

class C;
C foo();
Run Code Online (Sandbox Code Playgroud)

这是一对有效的声明.C仅仅在声明函数时不需要完全定义.但是如果我们要添加以下功能:

class C;
C foo();
inline C bar() { return foo(); }
Run Code Online (Sandbox Code Playgroud)

然后突然C需要一个完全定义的类型.但有了保证的复制权限,其成员都不是必需的.没有复制甚至移动,该值在其他地方初始化,并且仅在调用者(to bar)的上下文中被销毁.

所以为什么?标准中有什么禁止它?

小智 14

出于兼容性原因和/或效率,保证副本省略有例外.即使在可以保证复制省略的情况下,也可以复制普通的可复制类型.你是对的,如果这不适用,那么编译器将能够生成正确的代码而不知道任何细节C,甚至不知道它的大小.但编译器确实需要知道这是否适用,为此,它仍然需要完整的类型.

根据https://timsong-cpp.github.io/cppwp/class.temporary:

15.2临时对象[class.temporary]

1创建临时对象

[...]

(1.2) - 当实现需要传递或返回一个简单可复制类型的对象时(见下文),和

[...]

3当类类型的对象X传递给函数或从函数返回时,如果每个复制构造函数,移动构造函数和析构函数X都是微不足道的或删除的,并且X至少有一个未删除的副本或移动构造函数,则允许实现创建一个临时对象来保存函数参数或结果对象.临时对象分别由函数参数或返回值构造,并且函数的参数或返回对象被初始化,就好像通过使用未删除的普通构造函数来复制临时对象(即使该构造函数不可访问或不会被选中)通过重载决策来执行对象的复制或移动).[  注意:允许此纬度允许类类型的对象传递给寄存器中的函数或从寄存器中的函数返回.-  结束说明  ]

  • 一些友好的链接与时髦的绿色突出显示:[1.2](http://eel.is/c++draft/class.temporary#1.2)和[3](http://eel.is/c++draft/class .temporary#3).(我喜欢这家伙的网站). (2认同)

Red*_*ave 8

这与复制椭圆无关.在foo应该返回一个C值.只要你只是传递一个引用或指针foo,就可以了.一旦你试图调用foo- 就像在这种情况下一样bar- 它的参数和返回值的大小必须在手边; 知道这一点的唯一有效方式是提供所需类型的完整声明.如果签名使用了引用或指针,则所有必需的信息都存在,您可以在没有完整类型声明的情况下执行.这种方法有一个名称:pimpl ==指向IMPLementaion的指针,它被广泛用作隐藏闭源库发行版中细节的手段.


xsk*_*xzr 6

规则在于[basic.lval]/9:

除非另有说明([dcl.type.simple]),prvalue应始终具有完整类型或空白类型; ...

  • 我认为问题是*这条规则真的需要吗?*(在此背景下) (7认同)