完美的转发和功能参数绑定的模糊性

时间:2013-09-18 19:20:37

标签: c++ c++11

我正在尝试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)

2 个答案:

答案 0 :(得分:7)

  

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

那不是真的。如果您移除g(int&)重载,则会调用g(int)。当两者都被宣布时它是不明确的,因为两者都是可行的候选者并且不需要转换。

答案 1 :(得分:4)

添加Jonathan Wakelyanswer

首先,该问题与完美转发无关,我们可以从图片中删除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 &)无法接受rvalues。

现在将g(int &)替换为g(int &&)。后一个函数只能采用非const rvalues。因此,呼叫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&&)