【问题标题】:Overload ambiguity when passing R-value to function that takes L-value将 R 值传递给采用 L 值的函数时重载歧义
【发布时间】:2012-07-24 02:09:52
【问题描述】:

我有 2 个重载函数 - 一个采用 L 值,另一个采用 R 值。目的是使函数可以像这样调用:

Obj obj;
foo(obj);

或者:

foo(Obj());

所以,我写了两个重载函数:

template <class T>
void foo(T& v)
{
  /* ... function body code goes here ... */
}

template <class T>
void foo(T&& v)
{
    foo(v);
}

int main()
{
    foo(int(5));
}

R 值重载只需要委托给 L 值重载。按照我的理解,一旦我进入函数体,任何使用v 都会给我一个L 值参考,除非我特别使用std::movestd::forward。所以在 R 值重载中调用 foo(v) 应该会自动调用 L 值版本(而不是递归)。

但是,编译器抱怨歧义:

test.cpp: In function ‘void foo(T&&) [with T = int]’:
test.cpp:305:12:   instantiated from here
test.cpp:299:2: error: call of overloaded ‘foo(int&)’ is ambiguous

我不明白为什么这是模棱两可的。在 R 值重载中对 foo() 的调用应该清楚地调用 L 值版本。那为什么不编译呢?

【问题讨论】:

    标签: c++ c++11 rvalue-reference


    【解决方案1】:

    短版:尝试更新您的编译器。您的版本没有实现 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1164

    您的第二个模板是“完美转发”模板。 T&amp;&amp; 类型的任何函数模板形参,其中T 是一个模板形参,当实参是右值时,该模板形参将推导出为X(其中X 是实参类型),如果是X&amp;参数是一个左值。

    在您的情况下,您传递了一个右值,因此T 被推导出为Obj(在您的真实代码中为int)。如果您传递了一个变量名或其他左值,那么您的第二个模板将具有参数类型Obj&amp;(T 将是Obj&amp;,而应用于此类类型的&amp;&amp; 将保持Obj&amp;)。

    但是另一个模板也有这样的参数类型。因此,在重载解析期间,参数到参数的转换是相同的(完美匹配),并且需要检查另一个标准,即两个模板的 特异性,在 部分排序 em> 规则。如果一个模板比另一个模板更专业,那么它将由编译器选择。如果没有比另一个更专业的模板,最终的歧义就会上升。

    在这种情况下,第一个模板比第二个模板更专业,因此编译器最终应该调用第一个模板。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-13
      • 2012-05-07
      • 1970-01-01
      • 2017-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多