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

2024-10-26


1467. List-initialization of aggregate from same-type object

Section: 9.4.5  [dcl.init.list]     Status: CD4     Submitter: Jason Merrill     Date: 2012-02-06

[Moved to DR at the November, 2014 meeting.]

The current list-initialization rules do not provide for list-initialization of an aggregate from an object of the same type:

  struct X {
    X() = default;
    X(const X&) = default;
  #ifdef OK
    X(int) { }
  #endif
  };

  X x;
  X x2{x}; // error, {x} is not a valid aggregate initializer for X

Suggested resolution:

Change 9.4.5 [dcl.init.list] paragraph 3 as follows:

List-initialization of an object or reference of type T is defined as follows:

Additional notes (September, 2012):

(See messages 22368, 22371 through 22373, 22388, and 22494.)

It appears that 12.2.4.2.6 [over.ics.list] will also need to be updated in parallel with this change. Alternatively, it may be better to change 9.4.2 [dcl.init.aggr] instead of 9.4.5 [dcl.init.list] and 12.2.4.2.6 [over.ics.list].

In a related note, given

  struct NonAggregate {
    NonAggregate() {}
  };

  struct WantsIt {
    WantsIt(NonAggregate);
  };

  void f(NonAggregate n);
  void f(WantsIt);

  int main() {
    NonAggregate n;
    // ambiguous!
    f({n});
  }

12.2.4.2.6 [over.ics.list] paragraph 3 says that the call to f(NonAggregate) is a user-defined conversion, the same as the call to f(WantsIt) and thus ambiguous. Also,

    NonAggregate n;
    // #1 (n -> NonAggregate = Identity conversion)
    NonAggregate m{n};
    // #2 ({n} -> NonAggregate = User-defined conversion}
    // (copy-ctor not considered according to 12.2.4.2 [over.best.ics] paragraph 4)
    NonAggregate m{{n}};

Finally, the suggested resolution simply says “initialized from,” without specifying whether that means direct initialization or copy initialization. It should be explicit about which is intended, e.g., if it reflects the kind of list-initialization being done.

Proposed resolution (February, 2014) [SUPERSEDED]:

  1. Change 9.4.5 [dcl.init.list] paragraph 3 as follows:

  2. List-initialization of an object or reference of type T is defined as follows:

  3. Delete the final bullet of 12.2.4.2 [over.best.ics] paragraph 4, as follows:

  4. However, if the target is

    and the constructor or user-defined conversion function is a candidate by

    user-defined conversion sequences are not considered. [Note:...

  5. Insert the following two paragraphs between 12.2.4.2.6 [over.ics.list] paragraphs 1 and 2, moving the footnote from the current paragraph 3 to the second inserted paragraph:

  6. When an argument is an initializer list (9.4.5 [dcl.init.list]), it is not an expression and special rules apply for converting it to a parameter type.

    If the parameter type is a class C and the initializer list has a single element of type cv U, where U is C or a class derived from C, the implicit conversion sequence is the one required to convert the element to the parameter type.

    Otherwise, if the parameter type is a character array [Footnote: Since there are no parameters of array type, this will only occur as the underlying type of a reference parameter. —end footnote] and the initializer list has a single element that is an appropriately typed string literal (9.4.3 [dcl.init.string]), the implicit conversion is the identity conversion.

    If Otherwise, if the parameter type is std::initializer_list<X> and...

    Otherwise, if the parameter type is “array of N X[Footnote: ... —end footnote], if the initializer list has...

  7. Change 12.2.4.2.6 [over.ics.list] paragraph 7 as follows:

  8. Otherwise, if the parameter type is not a class:

  9. Change 12.2.4.3 [over.ics.rank] paragraph 3 as follows:

  10. Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

This resolution also resolves issues 1490, 1589, and 1631.

Notes from the February, 2014 meeting:

The resolution above does not adequately address the related issue 1758. It appears that conversion functions and constructors must be handled separately.

Proposed resolution (June, 2014):

  1. Change 9.4.5 [dcl.init.list] paragraph 3 as follows:

  2. List-initialization of an object or reference of type T is defined as follows:

  3. Change 12.2.2.8 [over.match.list] paragraph 1 as follows:

  4. When objects of non-aggregate class type T are list-initialized (9.4.5 [dcl.init.list]) such that 9.4.5 [dcl.init.list] specifies that overload resolution is performed according to the rules in this section, overload resolution selects the constructor...
  5. Change 12.2.4.2 [over.best.ics] paragraph 4 as follows:

  6. ...and the constructor or user-defined conversion function is a candidate by

    user-defined conversion sequences are not considered.

  7. Change 12.2.4.2.6 [over.ics.list] paragraphs 1-2 as follows, moving the footnote from paragraph 3:

  8. When an argument is an initializer list (9.4.5 [dcl.init.list]), it is not an expression and special rules apply for converting it to a parameter type.

    If the parameter type is a class X and the initializer list has a single element of type cv U, where U is X or a class derived from X, the implicit conversion sequence is the one required to convert the element to the parameter type.

    Otherwise, if the parameter type is a character array [Footnote: Since there are no parameters of array type, this will only occur as the underlying type of a reference parameter. —end footnote] and the initializer list has a single element that is an appropriately-typed string literal (9.4.3 [dcl.init.string]), the implicit conversion sequence is the identity conversion.

    If Otherwise, if the parameter type is std::initializer_list<X> and...

  9. Change 12.2.4.2.6 [over.ics.list] paragraph 7 as follows:

  10. Otherwise, if the parameter type is not a class:

  11. Move the final bullet of 12.2.4.3 [over.ics.rank] paragraph 3 to the beginning of the list and change it as follows:

This resolution also resolves issues 1490, 1589, 1631, 1756, and 1758.