C ++的哪些更改使复制初始化可用于具有显式构造函数的类? [英] What changes to C++ made copy initialization work for class with explicit constructor?
问题描述
考虑以下代码:
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 asT
, 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屋!