This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-04-13
[Moved to DR at the November, 2014 meeting.]
The current list-initialization rules do not provide forlist-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 forX
Suggested resolution:
Change 9.5.5 [dcl.init.list] paragraph 3 as follows:
List-initialization of an object or reference of typeT isdefined as follows:
IfT is a class type and theinitializer list has a single element of typecvT ora class type derived fromT, the object is initialized fromthat element.
IfOtherwise, if T is an aggregate...
Additional notes (September, 2012):
It appears that 12.2.4.2.6 [over.ics.list] will also needto be updated in parallel with this change. Alternatively, it may bebetter to change 9.5.2 [dcl.init.aggr] instead of9.5.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 tof(NonAggregate) is a user-defined conversion, the same as thecall tof(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 “initializedfrom,” without specifying whether that means direct initializationor 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]:
Change 9.5.5 [dcl.init.list] paragraph 3 as follows:
List-initialization of an object or reference of typeT isdefined as follows:
IfT is a class type and the initializer listhas a single element of typecvU, whereU isT or a class derived fromT, the object is initializedfrom that element (by copy-initialization for copy-list-initialization, orby direct-initialization for direct-list-initialization).
Otherwise, ifT is a character array and theinitializer list has a single element that is an appropriately typedstring literal (9.5.3 [dcl.init.string]), initialization is done asdescribed in that section.
IfOtherwise, ifT is anaggregate...
Delete the final bullet of 12.2.4.2 [over.best.ics] paragraph4, as follows:
However, if the target is
the first parameter of a constructor or
the implicit object parameter of a user-defined conversionfunction
and the constructor or user-defined conversion function is a candidateby
12.2.2.4 [over.match.ctor], when the argument is thetemporary in the second step of a classcopy-initialization,or
12.2.2.5 [over.match.copy], 12.2.2.6 [over.match.conv], or12.2.2.7 [over.match.ref] (in all cases),
or
the second phase of 12.2.2.8 [over.match.list] when theinitializer list has exactly one element, and the target is the firstparameter of a constructor of classX, and the conversion istoX or reference to (possiblycv-qualified)X,user-defined conversion sequences are not considered. [Note:...
Insert the following two paragraphs between12.2.4.2.6 [over.ics.list] paragraphs 1 and 2, moving thefootnote from the current paragraph 3 to the second insertedparagraph:
When an argument is an initializer list (9.5.5 [dcl.init.list]), itis not an expression and special rules apply for converting it to aparameter type.
If the parameter type is a classC and the initializerlist has a single element of typecvU, whereUisC or a class derived fromC, the implicit conversionsequence is the one required to convert the element to the parametertype.
Otherwise, if the parameter type is a character array[Footnote: Since there are no parameters of array type, this willonly occur as the underlying type of a reference parameter. —endfootnote] and the initializer list has a single element that is anappropriately typed string literal (9.5.3 [dcl.init.string]), theimplicit conversion is the identity conversion.
IfOtherwise, if the parameter type isstd::initializer_list<X> and...Otherwise, if the parameter type is “array ofNX”
[Footnote: ... —endfootnote], if the initializer list has...
Change 12.2.4.2.6 [over.ics.list] paragraph 7 as follows:
Otherwise, if the parameter type is not a class:
if the initializer list has one elementthat is not itself aninitializer list, the implicit conversion sequenceis the one required to convert the element to the parameter type;[Example:...
...
Change 12.2.4.3 [over.ics.rank] paragraph 3 as follows:
Two implicit conversion sequences of the same form are indistinguishableconversion sequences unless one of the following rules applies:
...
List-initialization sequenceL1 is a better conversion sequence thanlist-initialization sequenceL2 if
L1 converts tostd::initializer_list<X>for someX andL2 does not, or, if not that,
L1 converts to type “arrayofN1T”,L2 converts to type “arrayofN2T”, andN1 is smallerthanN2
.,even if one of the above rules would otherwise apply.[Example:
void f1(int); // #1 void f1(std::initializer_list<long>); // #2 void g1() { f1({42}); } // chooses #2 void f2(std::pair<const char*, const char*>); // #3 void f2(std::initializer_list<std::string>); // #4 void g2() { f2({"foo","bar"}); } // chooses #4—end example]
This resolution also resolves issues1490,1589, and1631.
Notes from the February, 2014 meeting:
The resolution above does not adequately address the relatedissue 1758. It appears thatconversion functions and constructors must be handled separately.
Proposed resolution (June, 2014):
Change 9.5.5 [dcl.init.list] paragraph 3 as follows:
List-initialization of an object or reference of typeT isdefined as follows:
IfT is a class type and the initializerlist has a single element of typecvU,whereU isT or a class derivedfromT, the object is initialized from that element (bycopy-initialization for copy-list-initialization, or bydirect-initialization fordirect-list-initialization).
Otherwise, ifT is a character array and theinitializer list has a single element that is an appropriately-typedstring literal (9.5.3 [dcl.init.string]), initialization isperformed as described in that section.
IfOtherwise, ifT is anaggregate,Otherwise, if the initializer list has no elements...
Otherwise, ifT is a specialization ofstd::initializer_list<E>...
Otherwise, ifT is a class type...
Otherwise, if the initializer list has a single element oftypeE and eitherT is not a reference type orits referenced type is reference-related toE, theobject or reference is initialized from that element(bycopy-initialization for copy-list-initialization, or bydirect-initialization for direct-list-initialization); if anarrowing conversion (see below) is required to convert theelement toT, the program is ill-formed.[Example:...
Otherwise...
Change 12.2.2.8 [over.match.list] paragraph 1 as follows:
When objects of non-aggregate class typeT are list-initialized(9.5.5 [dcl.init.list])such that9.5.5 [dcl.init.list] specifies that overload resolution isperformed according to the rules in this section, overloadresolution selects the constructor...
Change 12.2.4.2 [over.best.ics] paragraph 4as follows:
...and the constructor or user-defined conversion function is acandidate by
12.2.2.4 [over.match.ctor], when the argument isthe temporary in the second step of a classcopy-initialization,or
12.2.2.5 [over.match.copy],12.2.2.6 [over.match.conv], or 12.2.2.7 [over.match.ref](in all cases),
or
the second phase of 12.2.2.8 [over.match.list] when theinitializer list has exactly one element, and the target is thefirst parameter of a constructor of classX, and theconversion is toX or reference to (possiblycv-qualified)X,user-defined conversion sequences are not considered.
Change 12.2.4.2.6 [over.ics.list] paragraphs 1-2 asfollows, moving the footnote from paragraph 3:
When an argument is an initializer list(9.5.5 [dcl.init.list]), it is not an expression and specialrules apply for converting it to a parameter type.
If the parameter type is a classX and theinitializer list has a single element of typecvU,whereU isX or a class derived fromX, the implicit conversion sequence is the one requiredto 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, thiswill only occur as the underlying type of a reference parameter.—end footnote] and the initializer list has a singleelement that is an appropriately-typed string literal(9.5.3 [dcl.init.string]), the implicit conversion sequence isthe identity conversion.
IfOtherwise, if the parameter type isstd::initializer_list<X> and...
Change 12.2.4.2.6 [over.ics.list] paragraph 7 asfollows:
Otherwise, if the parameter type is not a class:
if the initializer list has one elementthat isnot itself an initializer list, the implicit conversionsequence is the one required to convert the element to theparameter type; [Example:...
Move the final bullet of 12.2.4.3 [over.ics.rank] paragraph 3to the beginning of the list and change it asfollows:
List-initialization sequenceL1 is a betterconversion sequence than list-initialization sequenceL2if
L1 convertstostd::initializer_list<X> for someXandL2 does not, or, if not that,
L1 converts to type “array ofN1T”,L2 converts to type “arrayofN2 T”, andN1 is smallerthanN2.,
even if one of the other rules in this paragraph would otherwiseapply. [Example:
void f1(int); // #1 void f1(std::initializer_list<long>); // #2 void g1() { f1({42}); } // chooses #2 void f2(std::pair<const char*, const char*>); // #3 void f2(std::initializer_list<std::string>); // #4 void g2() { f2({"foo","bar"}); } // chooses #4
—end example]
This resolution also resolves issues1490,1589,1631,1756, and1758.