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

How to use forwarding to cast rvalue to lvalue reference?

当我不关心返回的 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;
}

这里根本不需要 std::forward。除了第二次重载中的 int&& i 外,您的参数都声明为 non-const 左值引用,因此您不能将右值传递给它们中的任何一个。而在int&&重载中,如果你想从右值函数中调用左值函数,你只需将参数命名为i,因为名称总是一个左值

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&&。但是,通过将 n 的副本作为普通 int 参数,对简单 int 参数的更改将允许此 test 进行编译。然后对 int i 的更改将被丢弃,即使您将 n 赋给了函数。删除的模板更匹配 const int 左值 n,因此它会导致 test 无法编译。如果您确实想要 func(d, n) 有效但对 n 没有影响的行为,只需取出已删除的模板即可。