将R值传递给采用L值的函数时出现过载歧义

时间:2012-07-24 02:09:53

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

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

一样调用
Obj obj;
foo(obj);

OR:

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

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值版本。那么为什么不编译?

1 个答案:

答案 0 :(得分:6)

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

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

在您的情况下,您传递了一个右值,因此T被推断为Obj(以及您实际代码中的int)。如果您传递了变量名称或其他值为左值的内容,则第二个模板的参数类型为Obj&(T为Obj&&&应用于此类型留下Obj&)。

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

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