如何使用转发将右值转换为左值引用?

时间:2019-05-13 17:07:45

标签: c++ perfect-forwarding lvalue-to-rvalue

当我不在乎返回的int数据时,我尝试使用重载函数隐藏将int引用传递给实用程序函数。为什么我需要使用T&而不是T作为模板参数?为什么需要将i定义为右值的中间函数?

class DataClass
{

};

template <typename T>
bool func(T& data, int& i) {
  i = 1;
  cout << "it worked!" << endl;
}

// I would like to remove this function
template <typename T>
bool func(T& data, int&& i) {
  return func(std::forward<T&>(data), std::forward<int&>(i));
}

template <typename T>
bool func(T& data) {
  // Why doesn't this line work?
  // return func(std::forward<T>(data), std::forward<int>(0));
  return func(std::forward<T&>(data), 0);
}

int main(int argc, char ** argv)
{
  DataClass d;
  func<DataClass>(d);
  return 0;
}

1 个答案:

答案 0 :(得分:1)

这里完全不需要std::forward。除了第二个重载中的int&& i之外,您的参数都声明为非常量左值引用,因此您无法将右值传递给其中的任何一个。并且在int&&重载中,如果要从rvalue函数调用lvalue函数,则可以只命名参数i,因为名称始终是lvalue。

template <typename T>
bool func(T& data, int& i) {
  i = 1;
  cout << "it worked!" << endl;
}

template <typename T>
bool func(T& data, int&& i) {
  return func(data, i);
}

template <typename T>
bool func(T& data) {
  return func(data, 0);
}

如果您想删除一个函数,请注意实际上是int&确实做了一些不同的事情:它将i更改为1。从技术上讲,右值重载也可以,但是具有在此之后,通常应忽略作为右值传递的值,因此调用者仅应指望func(T&, int&&)才能将消息打印到cout。而要使用不是左值的int ...就请使用int

template <typename T>
bool func(T& data, int& i) {
  i = 1;
  cout << "it worked!" << endl;
}

template <typename T>
bool func(T& data, int i=0) {
  return func(data, i); // effect on i is ignored.
}

// Okay to pass a const int?
template <typename T>
bool func(T&, const volatile int&&) = delete;

第三个删除的模板保留了原始代码的一种行为,尽管尚不清楚您是否确实想要这种行为。在功能中

void test() {
    DataClass d;
    const int n = 5;
    func(d, n);
}

...由于const int左值不能绑定到int&int&&上,因此原始代码将无法编译。但是,只需将参数int的副本更改为简单的test参数,对参数n的更改将允许此int进行编译。这样,即使您将int i赋予了功能,对n的更改也将被放弃。删除的模板与const int左值n更好地匹配,因此将导致test无法编译。如果您确实希望func(d, n)有效但对n没有影响的行为,只需取出删除的模板即可。