【问题标题】:How to use forwarding to cast rvalue to lvalue reference?如何使用转发将右值转换为左值引用?
【发布时间】:2019-05-13 17:07:44
【问题描述】:

当我不关心返回的 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 仅对转发引用有用。 T&amp; 不是这样的转发引用,所以你不应该在这里使用std::forward
  • 调用func(d) 不会将DataClass 的引用转发到func(d, 0)
  • 转发引用仅在您声明对推导模板参数的右值引用时才会出现。即template &lt;typename T&gt; bool func(T&amp;&amp; data)。 “转发引用”中的“转发”是指转发给定表达式的值类别(左值或右值),而不是值本身。

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


【解决方案1】:

这里根本不需要std::forward。除了第二个重载中的int&amp;&amp; i 之外,您的参数都声明为非常量左值引用,因此您不能将右值传递给它们中的任何一个。而在int&amp;&amp;重载中,如果要从右值函数调用左值函数,只需将参数命名为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&amp;,它实际上做了一些不同的事情:它将 i 更改为 1。从技术上讲,右值重载也可以,但它已作为此后,右值通常应被忽略,因此调用者应仅依靠func(T&amp;, int&amp;&amp;) 将消息打印到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&amp;int&amp;&amp;。但是更改为简单的int 参数将允许此test 编译,方法是将n 复制为普通int 参数。然后对 int i 的更改将被丢弃,即使您将 n 提供给该函数。删除的模板更适合const int左值n,因此会导致test无法编译。如果您确实想要func(d, n) 有效但对n 没有影响的行为,只需取出已删除的模板即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    相关资源
    最近更新 更多