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

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

最佳答案

列表初始化,当用于初始化引用时,会将列出的值转换为纯右值(又名:临时值),用于直接初始化引用。

因此 int &b{foo{}} 在功能上等同于 int &b(int(foo{}))。这是模棱两可的;它可以通过 operator intoperator int& 生成 int

但即使它没有歧义,您仍然会得到一个对纯右值的非 const 左值引用。这是非法的。所以这段代码永远不会起作用。

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


But in this case why does compiler accept #5?

因为列表初始化是一系列有优先级的规则。一个比我上面指出的规则具有更高优先级的规则是包含单个值的 braced-init-list 的情况,其类型与正在初始化的类型相同。 #5 和 6 正好符合这个要求,因为 dea 都是 int&

但是,如果您只是听取我的建议,而不是在不尝试创建对象时使用花括号初始化列表,那么您就不必担心这样的极端情况。

关于c++ - 如果声明了对类型的转换运算符和对类型的引用,为什么直接列表初始化会导致类型引用转换的歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41079111/

相关文章:

C++ 替代模板化数据成员

c++ - 什么时候允许编译器优化 auto+brace 样式初始化?

c++ - 列表初始化和复制省略

c++ - TinyXpath v_get_xpath_base,第二个参数

c++ - 函数的返回值如何工作?

c++ - VS2010 中的名称查找错误

java - 在将 String 转换为 Date 时,java.util.Date 和 java.sql.Date 之间存在歧义

c++ - 自定义大括号初始值设定项

c++ - OpenMP:Visual C++ 2008 和 2010 之间的巨大性能差异

c# - 使用 'Microsoft.Office.Interop.Word._Document.Close'时编译时警告