Files
2025-10-25 03:02:53 +03:00

196 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[over.ics.list]
# 12 Overloading [[over]](./#over)
## 12.2 Overload resolution [[over.match]](over.match#over.ics.list)
### 12.2.4 Best viable function [[over.match.best]](over.match.best#over.ics.list)
#### 12.2.4.2 Implicit conversion sequences [[over.best.ics]](over.best.ics#over.ics.list)
#### 12.2.4.2.6 List-initialization sequence [over.ics.list]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2484)
When an argument is an initializer list ([[dcl.init.list]](dcl.init.list "9.5.5List-initialization")), it is not an expression and special rules apply for converting it to a parameter type[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2488)
If the initializer list is a [*designated-initializer-list*](dcl.init.general#nt:designated-initializer-list "9.5.1General[dcl.init.general]") and the parameter is not a reference,
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]](dcl.init.aggr "9.5.2Aggregates")),
in which case the implicit conversion sequence is
a user-defined conversion sequence
whose second standard conversion sequence
is an identity conversion[.](#2.sentence-1)
[*Note [1](#note-1)*:
Aggregate initialization does not require that
the members are declared in designation order[.](#2.sentence-2)
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]](dcl.init.list "9.5.5List-initialization"))[.](#2.sentence-3)
[*Example [1](#example-1)*: struct A { int x, y; };struct B { int y, x; };void f(A a, int); // #1void f(B b, ...); // #2void g(A a); // #3void g(B b); // #4void h() { f({.x = 1, .y = 2}, 0); // OK; calls #1 f({.y = 2, .x = 1}, 0); // error: selects #1, initialization of a fails// due to non-matching member order ([[dcl.init.list]](dcl.init.list "9.5.5List-initialization")) g({.x = 1, .y = 2}); // error: ambiguous between #3 and #4} — *end example*]
— *end note*]
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2523)
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 X or a class derived from X, the implicit conversion sequence is the one
required to convert the element to the parameter type[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2530)
Otherwise, if the parameter type is a character array[106](#footnote-106 "Since there are no parameters of array type, this will only occur as the referenced type of a reference parameter.") and the initializer list has a single element that is an appropriately-typed[*string-literal*](lex.string#nt:string-literal "5.13.5String literals[lex.string]") ([[dcl.init.string]](dcl.init.string "9.5.3Character arrays")), the implicit conversion
sequence is the identity conversion[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2540)
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[.](#5.sentence-1)
This conversion can be a user-defined conversion even in
the context of a call to an initializer-list constructor[.](#5.sentence-2)
[*Example [2](#example-2)*: void f(std::initializer_list<int>);
f( {} ); // OK, f(initializer_list<int>) identity conversion f( {1,2,3} ); // OK, f(initializer_list<int>) identity conversion f( {'a','b'} ); // OK, f(initializer_list<int>) integral promotion f( {1.0} ); // error: narrowingstruct A { A(std::initializer_list<double>); // #1 A(std::initializer_list<std::complex<double>>); // #2 A(std::initializer_list<std::string>); // #3};
A a{ 1.0,2.0 }; // OK, uses #1void g(A);
g({ "foo", "bar" }); // OK, uses #3typedef int IA[3];void h(const IA&);
h({ 1, 2, 3 }); // OK, identity conversion — *end example*]
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2572)
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[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2582)
Otherwise, if the parameter is a non-aggregate class X and overload
resolution per [[over.match.list]](over.match.list "12.2.2.8Initialization by list-initialization") chooses a single best constructor C ofX to perform the initialization of an object of type X from the
argument initializer list:
- [(7.1)](#7.1)
If C is not an initializer-list constructor
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 has Exact Match rank if U is X,
or Conversion rank if U is derived from X[.](#7.1.sentence-1)
- [(7.2)](#7.2)
Otherwise, the implicit conversion sequence is a user-defined
conversion sequence whose second standard conversion sequence is an
identity conversion[.](#7.2.sentence-1)
If multiple constructors are viable but none is better than
the others, the implicit conversion sequence is the ambiguous conversion
sequence[.](#7.sentence-2)
User-defined conversions are allowed for conversion of the initializer
list elements to the constructor parameter types except as noted
in [[over.best.ics]](over.best.ics "12.2.4.2Implicit conversion sequences")[.](#7.sentence-3)
[*Example [3](#example-3)*: struct A { A(std::initializer_list<int>);};void f(A);
f( {'a', 'b'} ); // OK, f(A(std::initializer_list<int>)) user-defined conversionstruct B { B(int, double);};void g(B);
g( {'a', 'b'} ); // OK, g(B(int, double)) user-defined conversion g( {1.0, 1.0} ); // error: narrowingvoid f(B);
f( {'a', 'b'} ); // error: ambiguous f(A) or f(B)struct C { C(std::string);};void h(C);
h({"foo"}); // OK, h(C(std::string("foo")))struct D { D(A, C);};void i(D);
i({ {1,2}, {"bar"} }); // OK, i(D(A(std::initializer_list<int>{1,2}), C(std::string("bar")))) — *end example*]
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2636)
Otherwise, if the parameter has an aggregate type which can be initialized from
the initializer list according to the rules for aggregate
initialization ([[dcl.init.aggr]](dcl.init.aggr "9.5.2Aggregates")), the implicit conversion sequence is a
user-defined conversion sequence whose second standard conversion
sequence is an identity conversion[.](#8.sentence-1)
[*Example [4](#example-4)*: struct A {int m1; double m2;};
void f(A);
f( {'a', 'b'} ); // OK, f(A(int,double)) user-defined conversion f( {1.0} ); // error: narrowing — *end example*]
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2655)
Otherwise, if the parameter is a reference, see [[over.ics.ref]](over.ics.ref "12.2.4.2.5Reference binding")[.](#9.sentence-1)
[*Note [2](#note-2)*:
The rules in this subclause will apply for initializing the underlying temporary
for the reference[.](#9.sentence-2)
— *end note*]
[*Example [5](#example-5)*: struct A {int m1; double m2;};
void f(const A&);
f( {'a', 'b'} ); // OK, f(A(int,double)) user-defined conversion f( {1.0} ); // error: narrowingvoid g(const double &);
g({1}); // same conversion as int to double — *end example*]
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2677)
Otherwise, if the parameter type is not a class:
- [(10.1)](#10.1)
if the initializer list has one element that is not itself an initializer list,
the implicit conversion sequence is the one required to convert the element to
the parameter type;
[*Example [6](#example-6)*: void f(int);
f( {'a'} ); // OK, same conversion as char to int f( {1.0} ); // error: narrowing — *end example*]
- [(10.2)](#10.2)
if the initializer list has no elements, the implicit conversion sequence
is the identity conversion[.](#10.sentence-1)
[*Example [7](#example-7)*: void f(int);
f( { } ); // OK, identity conversion — *end example*]
[11](#11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/overloading.tex#L2701)
In all cases other than those enumerated above, no conversion is possible[.](#11.sentence-1)
[106)](#footnote-106)[106)](#footnoteref-106)
Since there are no parameters of array type,
this will only occur as the referenced type of a reference parameter[.](#footnote-106.sentence-1)