#include <iostream>
struct A{
A(int){
}
};
struct B{
B() = default;
B(A){
}
B(B const&){}
B(B&&){}
};
int main(){
B b({0});
}
For the given codes, the candidate functions are:
#1 B::B(A)
#2 B::B(const B&)
#3 B::B(B&&)
According to the standard, for #1, the object of type A is copy-list-initialized by {0} as A a = {0}
, A::A(int)
is considered for the initialization, so only the standard conversion within #1. For #2, it's an initialization of a reference form braced-init-list
which is the cause of [dcl.init.list]
Otherwise, if T is a reference type, a prvalue of the type referenced by T is generated. The prvalue initializes its result object by copy-list-initialization or direct-list-initialization, depending on the kind of initialization for the reference. The prvalue is then used to direct-initialize the reference. [ Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. — end note ]
So it equates with const B& = {0}
, in this initialization, the conversion function is B::B(A)
and the argument is 0
, so B tmp = {0}
and 'B::B(A)' is considered that parameter is initialized by argument 0
, as A parameter = 0
.
Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in [over.match.copy], and the best one is chosen through overload resolution...
So there's a user-defined conversion within #2 and the situation of #3 is the same as that of #2 and accroding to the [over.ics.rank],
a standard conversion sequence is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and...
The standard conversion is better than user-defined conversion, so #1 should be better than #2 and #3, but actually, g++ report the invocation is ambiguous, why? The error message is:
main.cpp: In function ‘int main()’:
main.cpp:12:10: error: call of overloaded ‘B(<brace-enclosed initializer list>)’ is ambiguous
B b({0});
^
main.cpp:8:3: note: candidate: B::B(A)
B(A){
^
main.cpp:6:8: note: candidate: constexpr B::B(const B&)
struct B{
^
main.cpp:6:8: note: candidate: constexpr B::B(B&&)
{0} -> A
,{0} -> const B&
,{0} -> B&&
are user-defined conversions. Why do you think{0} -> A
is a standard conversion sequence? – xskxzr0
toint
is identity conversion for A::A(int) – xmh0511A a{0}
is a conversion ? – xmh0511