3

我正在试验 C++11 的完美转发功能。Gnu g++ 编译器报告了函数参数绑定的歧义问题(错误显示在下面的源代码之后)。我的问题是为什么会这样,因为遵循函数参数绑定过程我没有看到歧义。我的推理如下:在 main() 中调用tf(a ) 绑定到 tf(int&) 因为a是一个左值。然后函数tf将左值引用int& a转发给函数g,因此函数void g(int &a)应该被唯一地调用。因此,我看不出模棱两可的原因。重载函数g(int a)时错误消失从代码中删除。这很奇怪,因为g(int a)不能成为与int &a绑定的候选者。

这是我的代码:

void g(int &&a)
{
  a+=30;
}

void g(int &a)
{
  a+=10;
}

void g(int a)   //existence of this function originates the ambiguity issue
{
  a+=20;
}

template<typename T>
void tf(T&& a)
{
  g(forward<T>(a));;
}

int main()
{
  int a=5;
  tf(a);
  cout<<a<<endl;
}

编译g++ -std=c++11 perfectForwarding.cpp报以下错误

perfectForwarding.cpp: In instantiation of ‘void tf(T&&) [with T = int&]’:
perfectForwarding.cpp:35:7:   required from here
perfectForwarding.cpp:24:3: error: call of overloaded ‘g(int&)’ is ambiguous
perfectForwarding.cpp:24:3: note: candidates are:
perfectForwarding.cpp:6:6: note: void g(int&&) <near match>
perfectForwarding.cpp:6:6: note:   no known conversion for argument 1 from ‘int’ to ‘int&&’
perfectForwarding.cpp:11:6: note: void g(int&)
perfectForwarding.cpp:16:6: note: void g(int)
4

2 回答 2

7

这很奇怪,因为g(int a)不能成为与int &a绑定的候选者。

这不是真的。如果您删除g(int&)重载,那么g(int)将被调用。当两者都被声明时,它是模棱两可的,因为两者都是可行的候选者并且不需要转换。

于 2013-09-18T19:32:11.130 回答
4

在Jonathan Wakely回答之上添加。

首先,这个问题与完美转发无关,我们可以tf从图片中删除。

暂时只考虑这段代码:

void g(int) {}

int main() {
    int a = 5;       // a is an lvalue
    g(a);            // ok
    g(std::move(a)); // std::move(a) casts a to an rvalue and this call is also ok
}

这说明了一个按值接受参数的函数可以同时接受左值和右值。

现在假设我们添加

void g(int &) {}

那么第一个调用 ,g(a);就变得模棱两可了,因为g(int &)它只能接受非左值const而没有别的。第二次调用,g(std::move(a))仍然可以并且仍然调用g(int),因为g(int &)不能接受右值。

现在替换g(int &)g(int &&). 后一个函数只能采用非const右值。因此通话g(a)正常并且通话g(int)。然而,g(std::move(a))现在是模棱两可的。

此时很明显,如果我们将三个重载放在一起,那么这两个调用就会变得模棱两可。实际上,没有理由拥有三个重载。根据类型T,我们通常有

  1. g(T)或者
  2. g(T&)或者
  3. g(const T&)或者
  4. g(const T&)g(T&&)
于 2013-09-19T07:41:37.847 回答