Title
Copy-list-initialization with explicit default constructors
Status
dr
Section
12.2.2.8 [over.match.list]
Submitter
Anoop Rana

Created on 2024-01-09.00:00:00 last changed 3 weeks ago

Messages

Date: 2024-02-16.23:23:05

CWG 2024-02-16

The fact that #2 considers all constructors was discussed (and established) in the C++11 timeframe when brace-initialization was first introduced. #1 should be consistent with that, even though the = is usually a clear sign that explicit constructors are not considered.

Date: 2024-02-16.23:23:05

Proposed resolution (approved by CWG 2024-02-16):

Change in 12.2.2.4 [over.match.ctor] paragraph 1 as follows:

When objects of class type are direct-initialized (9.4 [dcl.init]), copy-initialized from an expression of the same or a derived class type (9.4 [dcl.init]), or default-initialized (9.4 [dcl.init]), overload resolution selects the constructor. For direct-initialization or default-initialization that is not in the context of copy-initialization (including default-initialization in the context of copy-list-initialization), the candidate functions are all the constructors of the class of the object being initialized. For copy-initialization (including default initialization in the context of copy-initialization) Otherwise, the candidate functions are all the converting constructors (11.4.8.2 [class.conv.ctor]) of that class. The argument list is the expression-list or assignment-expression of the initializer. For default-initialization in the context of copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed.
Date: 2024-03-15.00:00:00

[Accepted as a DR at the March, 2024 meeting.]

(From submission #486.)

Consider:

  struct A {
     explicit A(int = 10);
     A() = default;   // converting constructor (11.4.8.2 [class.conv.ctor] paragraph 1)
  };

  A a = {};       // #1, copy-initialization

  int f(A);
  int x = f({});  // #2

  A b;            // #3

#1 and #2 are accepted by MSVC and EDG, but considered ambiguous by gcc and clang. #3 is rejected as ambiguous by all major implementations.

#1 is copy-list-initialization (9.4.5 [dcl.init.list] paragraph 1), and A has a default constructor, thus a is value-initialized (9.4.5 [dcl.init.list] bullet 3.4). The default constructors are user-provided, thus a is default-initialized (9.4.1 [dcl.init.general] bullet 8.1, 9.4.1 [dcl.init.general] bullet 7.1). Overload resolution then chooses a constructor according to 12.2.2.4 [over.match.ctor] paragraph 1:

... For copy-initialization (including default initialization in the context of copy-initialization), the candidate functions are all the converting constructors (11.4.8.2 [class.conv.ctor]) of that class. ...

Thus, the explicit constructor is not a candidate; #1 chooses the converting constructor.

In contrast, #2 uses the special rules for forming a list-initialization sequence (12.2.4.2.6 [over.ics.list] paragraph 7), which perform overload resolution according to 12.2.2.8 [over.match.list] paragraph 1, which considers all constructors for overload resolution (and makes the program ill-formed if an explicit constructor is chosen). For the example, overload resolution is ambiguous.

#3 performs default-initialization, and overload resolution then chooses a constructor according to 12.2.2.4 [over.match.ctor] paragraph 1:

... For direct-initialization or default-initialization that is not in the context of copy-initialization, the candidate functions are all the constructors of the class of the object being initialized. ...

In this case, the overload resolution is ambiguous.

History
Date User Action Args
2024-04-05 21:43:46adminsetstatus: ready -> dr
2024-03-21 12:19:10adminsetstatus: tentatively ready -> ready
2024-02-16 23:23:05adminsetmessages: + msg7610
2024-02-16 23:23:05adminsetstatus: open -> tentatively ready
2024-02-09 23:21:37adminsetmessages: + msg7598
2024-01-09 00:00:00admincreate