C++ Logo

std-discussion

Advanced search

Might be a vague wording about the worst conversion rule for list-initialization sequence.

From: jim x <xmh970252187_at_[hidden]>
Date: Thu, 31 Dec 2020 10:41:30 +0800
About the implicit conversion sequence for the parameter of type `
std::initializer_­list<X>`, the relevant rule is worded by:
>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.

So, consider this example:
````
#include <initializer_list>
struct A{
    operator short(){
        return 0;
    }
};
struct B{
    operator bool(){
        return 0;
    }
};
void fun(std::initializer_list<int>){}
void fun(std::initializer_list<bool>){}
int main(){
    fun({A{},B{}});
}
````
For the parameter type `std::initializer_list<int>`, regardless of the
conversion function of `A` or `B`, they all have the user-defined
conversion with the second standard conversion sequence
an integral promotion. So, which is the worst conversion?

For the parameter type `std::initializer_list<bool>`, from `A` to `bool`,
the conversion sequence comprises a user-defined conversion with the second
standard conversion an *integral conversion. *Rather, from `B` to `bool`,
a user-defined conversion with the second standard conversion a identity
conversion. Hence, the worst conversion for `std::initializer_list<bool>`
is that of from `A` to `bool`.

So, the key point falls at which conversion function is the worst
conversion for `std::initializer_list<int>`? If it is `A::operator int`,
then the following rule will apply to determine the best overload:
>User-defined conversion sequence U1 is a better conversion sequence than
another user-defined conversion sequence U2 if they contain the same
user-defined conversion function or constructor or they initialize the same
class in an aggregate initialization and in either case the second standard
conversion sequence of U1 is better than the second standard conversion
sequence of U2.

Otherwise, if `B::operator bool` is considered as the worst conversion for
`std::initializer_list<int>`, then the above rule cannot apply here. That
means calling `fun` will be ambiguous.

Here <https://godbolt.org/z/EbjTcE>is the result of the example, GCC
reports an ambiguous error. Instead, the other compilers chose `void
fun(std::initializer_list<int>)` for `fun({A{},B{}})`. It is vague here. I
think [over.ics.list#5] <https://eel.is/c++draft/over.ics.list#5> should
clarify for this example. The rule should be reworded, to point out which
is the worst conversion between these conversions when they are
indistinguishable, In order to against the other when performing overload
resolution.

Received on 2020-12-30 20:41:44