简体   繁体   English

显式默认构造函数

[英]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 and T is a class type with a default constructor, the object is value-initialized. - 否则,如果初始化列表没有元素且T是具有默认构造函数的类类型,则对象将进行值初始化。

[dcl.init]/8 [dcl.init] / 8

To value-initialize an object of type T means: 类型T的对象进行值初始化意味着:
... ...
— if T 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])或者是用户提供或删除的默认构造函数,那么该对象是默认初始化的;

[dcl.init]/7 [dcl.init] / 7

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.

相关问题 使用默认构造函数进行显式转换 - Explicit casting using default constructor 显式默认默认构造函数和聚合 - Explicit defaulted default constructor and aggregates std :: map默认构造函数是否显式? - Is the std::map default constructor explicit? 隐式与显式默认构造函数调用 - Implicit vs. Explicit Default Constructor Call 对成员对象的非默认显式构造函数的内联使用 - Inline use of non-default explicit constructor for a member object 没有初始化器或显式默认构造函数的空类是否可用作constexpr变量? - Is an empty class usable as a constexpr variable without an initializer or explicit default constructor? 如何应用使默认构造函数有条件地显式? - How can I apply make a default constructor conditionally explicit? 使用枚举和模板 arguments 正确定义显式默认构造函数 - Correct definition of explicit default constructor with enum and template arguments C ++显式声明在默认构造函数中触发警告 - C++ Explicit declaration triggers a warning in the default constructor 具有所有默认参数的显式构造函数不能从同一类的另一个构造函数调用 - Explicit constructor with all default arguments can't be called from another constructor of the same class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM