0
#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&&)
xskxzr
  • 12,442
  • 12
  • 37
  • 77
xmh0511
  • 7,010
  • 1
  • 9
  • 36
  • All the three conversions `{0} -> A`, `{0} -> const B&`, `{0} -> B&&` are user-defined conversions. Why do you think `{0} -> A` is a standard conversion sequence? – xskxzr Feb 26 '20 at 03:45
  • @xskxzr Becuase the standard [dcl.init.list],the constructor is considered to directly initialize the reuslt object,and covert `0` to `int` is identity conversion for A::A(int) – xmh0511 Feb 26 '20 at 03:47
  • @xskxzr or in other word,Do you think `A a{0}` is a conversion ? – xmh0511 Feb 26 '20 at 03:56

2 Answers2

0

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.

xskxzr
  • 12,442
  • 12
  • 37
  • 77
  • As the above comment I said,Do you think `A a{0}` is a conversion,I think it's not and In my understanding ,in the short,the copy-list-initialization is basiclly the same as the direct-list-initialization except the consider contructors are declared with explicit,or if you can find the standard about copy-list-initialization that said {0} -> A is a conversion ,would you pass the quote here – xmh0511 Feb 26 '20 at 04:04
  • For the {0} -> A is a conversion ,I can give a example to prove it is not,such as `struct Data { Data(int) { } }; struct A { A(Data) { } };int main() { A a = { 0 }; }` as you said if {0}->A is a user-defined conversion, then 0 -> Data also a user-defined conversion,the standard said in a conversion sequence ,only have single user-defined conversion ,obviously,{0} -> A does not user-defined conversion – xmh0511 Feb 26 '20 at 04:18
  • @jackX I don't understand, a conversion sequence is naturally formed through initialization. Are you seeking for [\[over.best.ics\]/1](https://timsong-cpp.github.io/cppwp/over.best.ics#1)? – xskxzr Feb 26 '20 at 05:41
  • yes,`a conversion sequence is naturally formed through initialization`, then how do you interpret the case I mentioned in the comment,as you said that you think `{0} - > A` is a user-defined conversion ,then `0->Data` is another,so there have two user-defined conversion in the conversion sequence(ill-formed) – xmh0511 Feb 26 '20 at 06:26
  • @jackX To initialize `A` with `{0}`, the constructor `A(Data)` is selected and is used to complete the conversion, there is only one user-defined conversion. The conversion `0 -> Data` is a nested conversion due to the call to `A(Data)` (and subsequent overload resolution). It makes no sense to concatenate the two conversions while one is nested in the other. – xskxzr Feb 26 '20 at 07:09
  • ok ,you say 0->Data is a user-defined conversion ,then if `struct A{ A(int){ } };` the A defined like this,A a = {0},then 0->int is a user-defined according to you said?But actually ,It it not,so I think A::A({0}),there's no user-defined conversion – xmh0511 Feb 26 '20 at 07:21
  • assume A defined as `struct A{ A(int){ } };` why I say there's no user-defined conversion for `A a = {0};` becuase `A(int)` is selected by passing the value 0,and 0->int ,only standard conversion,However for `A a = 0;`,userdefined conversion perform,convert 0 to A ,then use the reuslt to directly initialize `a` – xmh0511 Feb 26 '20 at 07:37
  • @jackX See [\[over.best.ics\]/6](https://timsong-cpp.github.io/cppwp/over.best.ics#6): "... [ Note: When the parameter has a class type, this is a conceptual conversion defined for the purposes of [over]; the actual initialization is defined in terms of constructors and is not a conversion. — end note ] ..." I was talking about the conceptual conversion in the comments above. Sorry if it causes misunderstanding. – xskxzr Feb 26 '20 at 09:44
  • So,your means is that the copy-list-initialization occured within overload resolution is a user-defined conversion ,right? – xmh0511 Feb 26 '20 at 10:44
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/208563/discussion-between-xskxzr-and-jack-x). – xskxzr Feb 26 '20 at 11:33
  • another quesion is related to this question [here](https://stackoverflow.com/questions/60414790/is-the-copy-list-initialization-for-class-object-a-user-defined-conversion?noredirect=1#comment106878101_60414790) – xmh0511 Feb 27 '20 at 01:41
0

Answers are here,Because the argument is initializer list,so [over.ics.list] rules are performed when overload resolution.

[over.ics.list]/6

  1. 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.

xmh0511
  • 7,010
  • 1
  • 9
  • 36