c++ - 将 R 值传递给采用 L 值的函数时的重载歧义

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

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

Obj obj;
foo(obj);

或者:

foo(Obj());

因此,我编写了 2 个重载函数:

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));
}

右值重载只需要委托(delegate)给左值重载。按照我的理解,一旦进入函数体,对 v 的任何使用都会给我一个左值引用,除非我专门使用 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 值版本。那么为什么不能编译呢?

最佳答案

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

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

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

但是其他模板也有这样的参数类型。所以在重载决议期间,参数到参数的转换是相同的(完美匹配),并且需要检查另一个标准,即两个模板的特异性部分排序 规则。如果一个模板比另一个模板更专业,则编译器将选择它。如果没有比另一个更专业的模板,最终的歧义就会出现。

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

关于c++ - 将 R 值传递给采用 L 值的函数时的重载歧义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11623142/

相关文章:

c++ - key = pair 的多重映射

c++ - 如何使用在 visual studio 中显式加载的 C++ 类 dll

c++ - 无法弄清楚为什么使用 boost 库的多精度计算对我不起作用

c++ - 如何获取 std::thread() 的 Linux 线程 ID

c++ - 函数的右值引用和返回值

c++ - 在 C++ 中将非常量引用传递给右值

c++模板偏特化成员函数

c++ - 无法使 automake 使用 C++11

c++ - OpenACC 当前子句更新数据

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