这个问题在
this answer年的情况下有所上升.
考虑一个例子:
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; }
我不明白#2和#4为什么会导致歧义,而#1和#3则不会.所以问题是 – 为什么直接列表初始化会导致隐含的转换参考的歧义,如果转换类型和类型的引用被声明?
解决方法
列表初始化,当用于初始化引用时,将采用列出的值并将其转换为prvalue(aka:a temporary),用于直接初始化引用.
所以int& b {foo {}}在功能上等同于int& b(int(foo {})).哪个是模糊的它可以通过运算符int或运算符int& amp生成该int.
但是即使这不是模糊的,你仍然会得到一个非常量值参考的prvalue.哪个是非法的所以这段代码从来没有工作.
Braced-init-lists(大括号)初始化对象,而不是对对象的引用.如果您已经拥有一个对象并希望获得对象的引用,那么请勿使用braced-init-lists.
But in this case why does compiler accept #5?
因为列表初始化是一系列具有优先级的规则.一个比上面指出的优先级高的规则是一个包含单个值的braced-init-list的情况,它的类型与正在初始化的类型相同. #5和6恰好恰好符合该法案,因为d,e和a都是int& s.
但是,如果您只是采取我的建议,而不是在不尝试创建对象时使用braced-init-list,则不必担心像这样的角色.