[英]Explicit default constructor
This code compiles fine with GCC 5.X, MSVC, but GCC 6.X gives error: 此代码与GCC 5.X,MSVC编译良好,但GCC 6.X给出错误:
"converting to 'a' from initializer list would use explicit constructor 'a::a()'" , clang "chosen constructor is explicit in copy-initialization" .
“从初始化列表转换为'a'将使用显式构造函数'a :: a()'” ,clang “选择的构造函数在复制初始化中是显式的” 。
Removing explicit
or changing to ac{}
fixes the problem, but I`m curious why it works this way. 删除
explicit
或更改为ac{}
修复了问题,但我很好奇为什么它以这种方式工作。
class a
{
public:
explicit a () {}
};
struct b
{
a c;
};
int main() {
b d{};
}
b
is an aggregate . b
是一个聚合 。 When you initialize it using an initializer list, the elements in the list will initialize the first n members of the aggregate, where n is the number of elements in the list. 使用初始化列表初始化它时,列表中的元素将初始化聚合的前n个成员,其中n是列表中元素的数量。 The remaining elements of the aggregate are copy-list-initialized .
聚合的其余元素是copy-list-initialized 。
So in your example, c
will be copy-list-initialized , but that is ill-formed if the chosen constructor is explicit
, hence the error. 所以在你的例子中,
c
将被copy-list-initialized ,但是如果选择的构造函数是explicit
,那么这是错误的,因此错误。
The relevant standard quotes are 相关的标准报价是
[dcl.init.aggr]/3 [dcl.init.aggr] / 3
When an aggregate is initialized by an initializer list as specified in [dcl.init.list], the elements of the initializer list are taken as initializers for the elements of the aggregate.
当聚合由[dcl.init.list]中指定的初始化列表初始化时,初始化列表的元素将被视为聚合元素的初始化器。 The explicitly initialized elements of the aggregate are determined as follows:
聚合的显式初始化元素确定如下:
......
— If the initializer list is an initializer-list , the explicitly initialized elements of the aggregate are the first n elements of the aggregate, where n is the number of elements in the initializer list.- 如果初始化列表是初始化列表 ,则聚合的显式初始化元素是聚合的前n个元素,其中n是初始化列表中的元素数。
— Otherwise, the initializer list must be{}
, and there are no explicitly initialized elements.- 否则,初始化列表必须为
{}
,并且没有显式初始化的元素。
[dcl.init.aggr]/5 [dcl.init.aggr] / 5
For a non-union aggregate, each element that is not an explicitly initialized element is initialized as follows:
对于非联合聚合,每个不是显式初始化元素的元素都初始化如下:
......
— Otherwise, if the element is not a reference, the element is copy-initialized from an empty initializer list ([dcl.init.list]).- 否则,如果元素不是引用,则从空的初始化列表([dcl.init.list])复制初始化该元素。
The effect of copy initializing c
from an empty initializer list is described in 从空初始化列表中复制初始化
c
的效果描述于
[dcl.init.list]/3 [dcl.init.list] / 3
List-initialization of an object or reference of type
T
is defined as follows:列表初始化对象或类型
T
引用定义如下:
......
— Otherwise, if the initializer list has no elements andT
is a class type with a default constructor, the object is value-initialized.- 否则,如果初始化列表没有元素且
T
是具有默认构造函数的类类型,则对象将进行值初始化。
To value-initialize an object of type
T
means:对值类型
T
的对象进行值初始化意味着:
......
— ifT
is a (possibly cv-qualified) class type with either no default constructor ([class.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized;- 如果
T
是一个(可能是cv限定的)类类型,没有默认构造函数([class.ctor])或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;
To default-initialize an object of type
T
means:默认初始化
T
类型的对象意味着:
— If T is a (possibly cv-qualified) class type, constructors are considered.- 如果T是(可能是cv限定的)类类型,则考虑构造函数。 The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution.
枚举适用的构造函数([over.match.ctor]),并通过重载决策选择初始化程序()的最佳构造函数。 The constructor thus selected is called, with an empty argument list, to initialize the object.
使用空参数列表调用如此选择的构造函数来初始化对象。
[over.match.ctor] [over.match.ctor]
... For copy-initialization, the candidate functions are all the converting constructors of that class.
...对于复制初始化,候选函数是该类的所有转换构造函数。
[class.conv.ctor]/1 [class.conv.ctor] / 1
A constructor declared without the function-specifier
explicit
specifies a conversion from the types of its parameters (if any) to the type of its class.声明没有函数说明符
explicit
构造函数指定从其参数类型(如果有)到其类的类型的转换。 Such a constructor is called a converting constructor .这样的构造函数称为转换构造函数 。
In the example above, a
has no converting constructors, so overload resolution fails. 在上面的示例中,
a
没有转换构造函数,因此重载解析失败。 The (non-normative) example in [class.conv.ctor]/2 even contains a very similar case [class.conv.ctor] / 2中的(非规范)示例甚至包含一个非常类似的情况
struct Z { explicit Z(); explicit Z(int); explicit Z(int, int); }; Z c = {}; // error: copy-list-initialization
You can avoid the error by providing a default member initializer for c
您可以通过为
c
提供默认成员初始值设定项来避免错误
struct b
{
a c{}; // direct-list-initialization, explicit ctor is OK
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.