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

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

Nic*_*las 7

列表初始化,当用于初始化引用时,将获取列出的值并将它们转换为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,ea都是int&秒.

但是,如果您只是接受我的建议而不是在不尝试创建对象时使用braced-init-lists,那么您就不必担心像这样的角落情况.

  • 因为不是每个人都知道prvalue(例如,我自己).以下是其解释的链接:http://stackoverflow.com/a/3601661/783510 (3认同)
  • "Braced-init-lists(花括号)初始化对象,而不是对对象的引用.",这有点太简单了.`int a = 0;没有问题.int&b {a};`初始化引用的位置. (2认同)