问题
#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&&)
回答1:
All the three conversions {0} -> A
, {0} -> const B&
, {0} -> B&&
are user-defined conversions.
To convert {0}
to A
, another overload resolution happens and this time you face three constructors A(int)
, A(const A&)
and A(A&&)
. Since 0 -> int
is a standard conversion while both 0 -> const A&
and 0 -> A&&
are user-defined conversion, the conversion 0 -> int
wins and A(int)
is selected to convert {0}
to A
.
Your confusion comes from mixing the two overload resolutions.
回答2:
Answers are here,Because the argument is initializer list,so [over.ics.list] rules are performed when overload resolution.
[over.ics.list]/6
- Otherwise, if the parameter is a non-aggregate class X and overload resolution per [over.match.list] chooses a single best constructor C of X to perform the initialization of an object of type X from the argument initializer list:
- 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.
- Otherwise, the implicit conversion sequence is a user-defined conversion sequence with the second standard conversion sequence an identity conversion.
Hence,for these three candiate constructors,the parameter of them are all non-aggerate class type,so the implicit conversion sequence is used to convert the single element of the initializer list to corresponding parameter type of the constructor of parameter of constructor B
and therefore these conversion sequences are all user-defined conversion sequence and the second standard conversion sequence are all identity conversions.So the rank of them are indistinguishable.
来源:https://stackoverflow.com/questions/60406254/whats-the-rank-of-implicitly-conversion-for-copy-list-initialization