Explicit default constructor

后端 未结 1 1218
广开言路
广开言路 2021-02-07 03:49

This code compiles fine with GCC 5.X, MSVC, but GCC 6.X gives error:

\"converting to \'a\' from initializer list would use explicit constructor \'a:

相关标签:
1条回答
  • 2021-02-07 04:43

    b is an aggregate. 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. The remaining elements of the aggregate are 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.

    The relevant standard quotes are

    [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. 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.
    — Otherwise, the initializer list must be {}, and there are no explicitly initialized elements.

    [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]).

    The effect of copy initializing c from an empty initializer list is described in

    [dcl.init.list]/3

    List-initialization of an object or reference of type T is defined as follows:
    ...
    — Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.

    [dcl.init]/8

    To value-initialize an object of type T means:
    ...
    — 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;

    [dcl.init]/7

    To default-initialize an object of type T means:
    — If T is a (possibly cv-qualified) class type, constructors are considered. The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution. The constructor thus selected is called, with an empty argument list, to initialize the object.

    [over.match.ctor]

    ... For copy-initialization, the candidate functions are all the converting constructors of that class.

    [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. Such a constructor is called a converting constructor.

    In the example above, a has no converting constructors, so overload resolution fails. The (non-normative) example in [class.conv.ctor]/2 even contains a very similar case

      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

    struct b
    {
        a c{};  // direct-list-initialization, explicit ctor is OK
    };
    
    0 讨论(0)
提交回复
热议问题