为什么直接列表初始化会导致类型引用转换的歧义,如果声明了对类型的引用运算符和对类型的引用?

时间:2016-12-10 18:53:19

标签: c++ ambiguity list-initialization typecast-operator

问题出现在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则不然。所以问题是 - 为什么直接列表初始化会导致隐式强制转换引用歧义,如果声明了类型和类型引用的转换运算符?

1 个答案:

答案 0 :(得分:7)

列表初始化,当用于初始化引用时,将获取列出的值并将它们转换为prvalue(又名:临时),它将用于指导初始化引用。

因此int &b{foo{}}在功能上等同于int &b(int(foo{}))。哪个含糊不清;它可以通过intoperator int生成operator int&

但即使它不含糊,你仍然会得到一个非常数左值的prvalue引用。哪个是非法的。所以这段代码从不开始工作。

Braced-init-lists(花括号)初始化对象,而不是引用到对象。如果您已有一个对象并希望获得它的引用,请不要使用braced-init-lists。

  

但在这种情况下,为什么编译器会接受#5?

因为列表初始化是一系列具有优先级的规则。优先级高于我上面指出的优先级的规则是包含单个值的braced-init-list,其类型与正在初始化的类型相同。 #5和6恰好适合该帐单,因为dea都是int& s。

但是如果你只是接受我的建议而不是在你不尝试创建一个对象时使用braced-init-lists,那么你不必担心像这样的角落案例。