问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/41079111/why-does-direct-list-initialization-causes-ambiguity-for-type-reference-cast-if