what are the overload resolution rules of list-initialization

回眸只為那壹抹淺笑 提交于 2020-02-27 23:32:09

问题


there are some codes here

#include <iostream>
struct A {
    A(int) {}
};
struct B {
    B(A) {
        std::cout<<"0"<<std::endl;
    }
    B(B const&) {
        std::cout << "1" << std::endl;
    }
    B(B&&) {
        std::cout << "2" << std::endl;
    }
};
int main() {
    B b0{{0}}; // this is ok  #1
    B b( {0} ); //this is error #2
}

g++ report:

main.cpp: In function ‘int main()’:
main.cpp:17:11: error: call of overloaded ‘B(<brace-enclosed initializer list>)’ is ambiguous
  B b({ 0 });
           ^
main.cpp:12:2: note: candidate: B::B(B&&)
  B(B&&) {
  ^
main.cpp:9:2: note: candidate: B::B(const B&)
  B(B const&) {
  ^
main.cpp:6:2: note: candidate: B::B(A)
  B(A) {

clang report:

main.cpp:17:4: error: call to constructor of 'B' is ambiguous
        B b({ 0 });
          ^ ~~~~~
main.cpp:6:2: note: candidate constructor
        B(A) {
        ^
main.cpp:12:2: note: candidate constructor
        B(B&&) {
        ^
main.cpp:9:2: note: candidate constructor
        B(B const&) {
        ^
1 error generated.

{0} will convert to temporary object A and the contructor B(A) will be selected, #1 and #2 are all the "direct-constructor" form ,why #1 is ok ,#2 has three candidate constructor and is ambiguous?


回答1:


Because for #1, the copy and move constructors are disallowed by [over.best.ics]/4 (emphasized mine):

However, if the target is

  • the first parameter of a constructor or
  • the implicit object parameter of a user-defined conversion function

and the constructor or user-defined conversion function is a candidate by

  • [over.match.ctor], when the argument is the temporary in the second step of a class copy-initialization,

  • [over.match.copy], [over.match.conv], or [over.match.ref] (in all cases), or

  • the second phase of [over.match.list] when the initializer list has exactly one element that is itself an initializer list, and the target is the first parameter of a constructor of class X, and the conversion is to X or reference to cv X,

user-defined conversion sequences are not considered. [ Note: These rules prevent more than one user-defined conversion from being applied during overload resolution, thereby avoiding infinite recursion.  — end note ]

So it is the language rule that distinguishes ({...}) and {{...}}. Note the ({...}) case falls into [over.match.ctor] but the argument is NOT the temporary in the second step of a class copy-initialization, so the first bullet does not apply.

You can further read Issue 2076 to see it is intended to disallow the copy and move constructors for the inner brace in the {{...}} case:

The resolution of issue 1467 made some plausible constructs ill-formed. For example,

struct A { A(int); };
struct B { B(A); };
B b{{0}};

This is now ambiguous, because the text disallowing user-defined conversions for B's copy and move constructors was removed from 16.3.3.1 [over.best.ics] paragraph 4...




回答2:


Why B b( {0} ); does not work?

A a { 0 };
B b { 0 };

Those are both valid. So, in B b( { 0 }), what does { 0 } stand for? It could be an instance of A or B. Nobody knows, and that's why it's ambiguous. As your compiler states: there are 3 candidates:

B::B(A)
B::B(const B&)
B::B(B&&)

Why does B b0 { {0} }; work?

Because you simply call the constructor B::B(A). The copy/move constructors are not called here, only the constructor is. A copy constructor would only be invoked if you initialize the instance with an lvalue of another instance:

B b0 {};
B b1 { b0 }; // copy constructor

The same is valid for the move constructor:

B b0 {};
B b1 { std::move(b0) }; // move constructor

Now, if you pass an instance as a prvalue, it will call the constructor, because the instance can be constructed on the fly, that is: the prvalue does not need to be copied or moved, it can be directly constructed into b0. Example:

B b0 { {0} };

Here, {0} can be interpreted as a prvalue of type B, or of type A, but in both cases, the constructor is called.



来源:https://stackoverflow.com/questions/58930321/what-are-the-overload-resolution-rules-of-list-initialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!