Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does direct list initialization causes ambiguity for type reference cast if cast operators to the type and reference to the type are declared?

The question rose in context of this answer.

Consider an example:

struct foo {
    int value;
    operator int&(){ return value; }
    operator int(){ return value; }
};

int main () {
    int &a(foo{}); // #1
    //int &b{foo{}}; // #2 -- ambiguity
    int &c = foo{}; // #3
    //int &d = {foo{}}; // #4-- ambiguity
    int &d { a }; // #5
    int &e = { a }; // #6
    (void)a;
    (void)c;
    (void)d;
    (void)e;
}

I don't understand why does #2 and #4 cause ambiguity while #1 and #3 does not. So the question is - why does direct list initialization causes ambiguity for implicit cast to reference if cast operators to the type and reference to the type are declared?

like image 683
W.F. Avatar asked Dec 10 '16 18:12

W.F.


1 Answers

List initialization, when used to initialize a reference, will take the listed values and convert them into a prvalue (aka: a temporary), which will be used to direct initialize the reference.

So int &b{foo{}} is functionally equivalent to int &b(int(foo{})). Which is ambiguous; it could generate that int via operator int or operator int&.

But even if it wasn't ambiguous, you would still be getting a non-const lvalue reference to a prvalue. Which is illegal. So this code was never going to work.

Braced-init-lists (curly braces) initialize objects, not references to objects. If you already have an object and want to get a reference to it, don't use braced-init-lists.


But in this case why does compiler accept #5?

Because list initialization is a series of rules with priority. A rule that has a higher priority than the one I pointed out above is the case of a braced-init-list which contains a single value, who's type is identical to the type of what is being initialized. #5 and 6 just so happen to fit that bill, since d, e, and a are all int&s.

But if you just take my advice and not use braced-init-lists when you're not trying to create an object, you won't have to worry about corner-cases like that.

like image 97
Nicol Bolas Avatar answered Oct 04 '22 18:10

Nicol Bolas