C++ 如果声明了类型的强制转换运算符和类型的引用,为什么直接列表初始化会导致类型引用强制转换不明确?
这一问题是在经济衰退的背景下提出的 举个例子:C++ 如果声明了类型的强制转换运算符和类型的引用,为什么直接列表初始化会导致类型引用强制转换不明确?,c++,ambiguity,list-initialization,typecast-operator,C++,Ambiguity,List Initialization,Typecast Operator,这一问题是在经济衰退的背景下提出的 举个例子: 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
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不会。因此,问题是-如果声明了类型的强制转换运算符和类型的引用,为什么直接列表初始化会导致隐式强制转换引用不明确?列表初始化用于初始化引用时,将获取列出的值并将其转换为PR值(也称为临时值),它将用于直接初始化引用 所以
int&b{foo{}
在功能上等同于int&b(int(foo{}))
。这是含糊不清的;它可以通过操作符int
或操作符int&
生成int
但即使它不是含糊不清的,您仍然会得到一个对prvalue的非常量左值引用。这是违法的。所以这个代码永远不会起作用
大括号初始化列表(大括号)初始化对象,而不是对对象的引用。如果您已经有一个对象,并且希望获得对它的引用,那么不要使用带括号的init列表
但在这种情况下,编译器为什么接受#5 因为列表初始化是一系列具有优先级的规则。一个比我上面指出的优先级更高的规则是一个带括号的init列表,它包含一个值,谁的类型与被初始化的类型相同#5和6正好符合这个要求,因为
d
,e
,和a
都是int&
s
但是,如果您只是接受我的建议,在不尝试创建对象时不使用带大括号的init列表,那么您就不必担心这样的情况。
int&a(foo{})
是直接初始化int&b{foo{}
是直接列表初始化。它们不是一回事,因为不是每个人都知道prvalue(比如我自己)。下面是其解释的链接:但在这种情况下,编译器为什么接受#5?它不是类似于int&d(int(a))代码>?@Nicolas详尽地回答了我的问题!谢谢“带大括号的init列表(大括号)初始化对象,而不是对对象的引用。”,这有点过于简化了。inta=0没有问题;int&b{a}代码>它初始化引用的地方。@johanneschaub-litb:这是一种简化,是的,但非常有用。它避免了上述情况。