C ++的哪些更改使复制初始化可用于具有显式构造函数的类? [英] What changes to C++ made copy initialization work for class with explicit constructor?

查看:107
本文介绍了C ++的哪些更改使复制初始化可用于具有显式构造函数的类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

struct X{
    explicit X(){}
    explicit X(const X&){}
};

void foo(X a = X()){}

int main(){}

使用C ++ 14标准,GCC 7.1和clang 4.0 拒绝代码,这就是我预料到了.

Using C++14 standard, both GCC 7.1 and clang 4.0 rejects the code, which is what I expected.

但是,使用C ++ 17(-std=c++1z),它们都接受代码.什么规则改变了?

However, using C++17 (-std=c++1z), they both accept the code. What rule changed?

对于两个编译器都表现出相同的行为,我怀疑这是一个错误.但是据我所知,最新草案仍然说,默认参数使用 copy-initialization 1 的语义.同样,我们知道explicit构造函数将只允许直接初始化 2 .

For both compilers to exhibit this same behavior, I doubt this to be a bug. But as far as I can tell, the latest draft still says, default argument uses the semantics of copy-initialization 1. Again, we know that explicit constructors will only allow direct initialization 2.

1 : dcl.fct .default/5 ; 2 : class.conv.ctor/2

1: dcl.fct.default/5; 2: class.conv.ctor/2

推荐答案

因为 copy Elision 从C ++ 17开始的更改;对于这种情况,必须进行优化.

Because the behavior of copy elision changes from C++17; for this case the optimization is mandatory.

在以下情况下,要求编译器省略 类对象的copy-和move-构造函数,即使复制/移动 构造函数和析构函数具有明显的副作用:

Under the following circumstances, the compilers are required to omit the copy- and move- constructors of class objects even if copy/move constructor and the destructor have observable side-effects:

  • 在初始化中,如果初始化器表达式为prvalue且 源类型的cv-非限定版本与 目标的类,初始化器表达式用于 初始化目标对象:

  • In initialization, 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:

T x = T(T(T())); // only one call to default constructor of T, to initialize x

,对于复制初始化:

副本初始化的影响是:

The effects of copy initialization are:

  • 首先,如果T是类类型并且初始化程序是prvalue 其cv不合格类型与T属于同一类的表达式 初始化表达式本身,而不是一个临时物化 从中用于初始化目标对象:请参见复制 省略(自C ++ 17起)

  • First, if T is a class type and the initializer is a prvalue expression whose cv-unqualified type is the same class as T, the initializer expression itself, rather that a temporary materialized from it, is used to initialize the destination object: see copy elision (since C++17)

如果T是类类型,并且该类型的cv不合格版本 另一个是T或从T派生的类,该类的非显式构造函数 检查T并通过重载分辨率选择最佳匹配. 然后调用构造函数以初始化对象.

If T is a class type and the cv-unqualified version of the type of other is T or a class derived from T, the non-explicit constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.

这意味着对于X a = X()a将直接默认构造,复制/移动构造函数及其副作用将被完全省略.不会选择用于重载解析的非显式构造函数,这在C ++ 14(及之前)中是必需的.对于这些保证的情况,复制/移动构造函数不参与,因此它们是否为explicit都无关紧要.

That means for X a = X(), a will be default constructed directly, the copy/move constructors and their side effects will be omiited completely. The selection of non-explicit constructors for overload resolution won't take place, which is required in C++14 (and before). For these guaranteed cases, the copy/move constructors don't participate in, then it won't matter whether they're explicit or not.

这篇关于C ++的哪些更改使复制初始化可用于具有显式构造函数的类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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