This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


2742. Guaranteed copy elision for brace-initialization from prvalue

Section: 9.4.5  [dcl.init.list]     Status: drafting     Submitter: Jim X     Date: 2023-06-06

Consider:

  struct A {
    A();
    A(A const&) = delete;
  };
  int main(){
    A a = A(A(A())); // #1 
    A b = A{A{A{}}}; // #2 
  }

#1 is well-formed per 9.4.1 [dcl.init.general] bullet 16.6.1. However, even though #2 is intended to have a similar effect, the relevant rule excludes non-aggregates, making the example ill-formed (because the relevant constructor is deleted); see 9.4.5 [dcl.init.list] bullet 3.2:

If T is an aggregate class and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

There is implementation divergence: gcc and clang accept, MSVC rejects.

See also issue 2311.

Suggested resolution:

Change in 9.4.5 [dcl.init.list] bullet 3.2 as follows:

If T is an aggregate class a class type and the initializer list has a single element of type cv U, where U is T or a class derived from T, the object is initialized from that element (by copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization).

CWG 2024-03-01

Recent MSVC no longer rejects the example. The suggested resolution would revert issue 2137, which is not desirable. The consensus is to try an initializer-list constructor first and then fall back to copy-initialization (with guaranteed copy elision). A change to 12.2.4.2.6 [over.ics.list] may be necessary.