[over.ics.list] (original) (raw)

12 Overloading [over]

12.4 Overload resolution [over.match]

12.4.3 Best viable function [over.match.best]

12.4.3.1 Implicit conversion sequences [over.best.ics]

12.4.3.1.5 List-initialization sequence [over.ics.list]

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

If the initializer list is a designated-initializer-list, a conversion is only possible if the parameter has an aggregate type that can be initialized from the initializer list according to the rules for aggregate initialization ([dcl.init.aggr]), in which case the implicit conversion sequence is a user-defined conversion sequence whose second standard conversion sequence is an identity conversion.

[ Note

:

Aggregate initialization does not require that the members are declared in designation order.

If, after overload resolution, the order does not match for the selected overload, the initialization of the parameter will be ill-formed ([dcl.init.list]).

[ Example

:

struct A { int x, y; }; struct B { int y, x; }; void f(A a, int);
void f(B b, ...);
void g(A a);
void g(B b);
void h() { f({.x = 1, .y = 2}, 0);
f({.y = 2, .x = 1}, 0);

g({.x = 1, .y = 2});
}

end example

]

end note

]

Otherwise, if the parameter type is an aggregate class X and the initializer list has a single element of type cv U, where U is Xor 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 array125and the initializer list has a single element that is an appropriately-typedstring-literal ([dcl.init.string]), the implicit conversion sequence is the identity conversion.

Otherwise, if the parameter type is std​::​initializer_­list<X>and all the elements of the initializer list can be implicitly converted to X, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X, or if the initializer list has no elements, the identity conversion.

This conversion can be a user-defined conversion even in the context of a call to an initializer-list constructor.

[ Example

:

void f(std::initializer_list); f( {} );
f( {1,2,3} );
f( {'a','b'} );
f( {1.0} );

struct A { A(std::initializer_list);
A(std::initializer_list<complex>);
A(std::initializer_liststd::string);
}; A a{ 1.0,2.0 };

void g(A); g({ "foo", "bar" });

typedef int IA[3]; void h(const IA&); h({ 1, 2, 3 });

end example

]

Otherwise, if the parameter type is “array of N X” or “array of unknown bound of X”, if there exists an implicit conversion sequence from each element of the initializer list (and from {} in the former case if N exceeds the number of elements in the initializer list) to X, the implicit conversion sequence is the worst such implicit conversion sequence.

Otherwise, if the parameter is a non-aggregate class X and overload resolution per [over.match.list] chooses a single best constructor C ofX to perform the initialization of an object of type X from the argument initializer list:

If multiple constructors are viable but none is better than the others, the implicit conversion sequence is the ambiguous conversion sequence.

User-defined conversions are allowed for conversion of the initializer list elements to the constructor parameter types except as noted in [over.best.ics].

[ Example

:

struct A { A(std::initializer_list); }; void f(A); f( {'a', 'b'} );

struct B { B(int, double); }; void g(B); g( {'a', 'b'} );
g( {1.0, 1.0} );

void f(B); f( {'a', 'b'} );

struct C { C(std::string); }; void h(C); h({"foo"});

struct D { D(A, C); }; void i(D); i({ {1,2}, {"bar"} });

end example

]

Otherwise, if the parameter has an aggregate type which can be initialized from the initializer list according to the rules for aggregate initialization, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion.

[ Example

:

struct A { int m1; double m2; };

void f(A); f( {'a', 'b'} );
f( {1.0} );

end example

]

Otherwise, if the parameter is a reference, see [over.ics.ref].

[ Note

:

The rules in this subclause will apply for initializing the underlying temporary for the reference.

end note

]

[ Example

:

struct A { int m1; double m2; };

void f(const A&); f( {'a', 'b'} );
f( {1.0} );

void g(const double &); g({1});

end example

]

Otherwise, if the parameter type is not a class:

In all cases other than those enumerated above, no conversion is possible.