W.F*_*.F. 10 c++ ambiguity typecast-operator list-initialization
在这个答案的背景下,问题就出现了.
考虑一个例子:
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;
}
Run Code Online (Sandbox Code Playgroud)
我不明白为什么#2和#4引起歧义,而#1和#3则不然.所以问题是 - 为什么直接列表初始化会导致隐式强制转换引用的歧义,如果声明类型和对类型的引用的转换运算符?
列表初始化,当用于初始化引用时,将获取列出的值并将它们转换为prvalue(又名:临时),它将用于指导初始化引用.
所以int &b{foo{}}在功能上等同于int &b(int(foo{})).哪个含糊不清; 它可以int通过operator int或生成operator int&.
但即使它没有含糊不清,你仍然会得到一个非常数左值的prvalue引用.哪个是非法的.所以这段代码永远不会起作用.
Braced-init-lists(花括号)初始化对象,而不是对象的引用.如果您已有一个对象并希望获得对它的引用,请不要使用braced-init-lists.
但在这种情况下,为什么编译器会接受#5?
因为列表初始化是一系列具有优先级的规则.优先级高于我上面指出的优先级的规则是braced-init-list包含单个值的情况,其类型与正在初始化的类型相同.#5,6只所以发生,以适应该法案,因为d,e和a都是int&秒.
但是,如果您只是接受我的建议而不是在不尝试创建对象时使用braced-init-lists,那么您就不必担心像这样的角落情况.