为什么我应该使用std::forward

Why should I use std::forward?

本文关键字:forward std 我应该 为什么      更新时间:2023-10-16

在下面的代码中,为什么在传递参数时要使用std::forward

class Test {
  public:
  Test() {
      std::cout << "ctor" << std::endl;
  }
  Test(const Test&) {
      std::cout << "copy ctor" << std::endl;
  }
  Test(const Test&&) {
      std::cout << "move ctor" << std::endl;
  }
};
template<typename Arg>
void pass(Arg&& arg) {
    // use arg..
    return; 
}
template<typename Arg, typename ...Args>
void pass(Arg&& arg, Args&&... args)
{
    // use arg...
    return pass(args...); // why should I use std::forward<Arg>(args)... ?
}
int main(int argc, char** argv)
{
    pass(std::move<Test>(Test()));
    return 0;
}

无论是否使用std::forward,代码都不会显示任何复制/移动。

关于std::forward的作用及其工作方式(如这里和这里),有很多不错的帖子。

简而言之,它保留了其参数的值类别。完美转发是为了确保提供给一个函数的参数被转发给另一个函数(或在函数中使用),该函数具有与最初提供的值类别相同的值类别(基本上是r值与l值)。它通常与可能发生引用折叠的模板函数一起使用(涉及通用/转发引用)。

请考虑下面的代码示例。移除std::forward将打印出requires lvalue,而添加std::forward将打印出requires rvaluefunc是基于它是右值还是左值而过载的。在没有std::forward的情况下调用它会调用不正确的重载。在这种情况下,std::forward是必需的,因为pass是用右值调用的。

#include <utility>
#include <iostream>
class Test {
  public:
  Test() {
      std::cout << "ctor" << std::endl;
  }
  Test(const Test&) {
      std::cout << "copy ctor" << std::endl;
  }
  Test(Test&&) {
      std::cout << "move ctor" << std::endl;
  }
};
void func(Test const&)
{
    std::cout << "requires lvalue" << std::endl;
}
void func(Test&&)
{
    std::cout << "requires rvalue" << std::endl;
}
template<typename Arg>
void pass(Arg&& arg) {
    // use arg here
    func(std::forward<Arg>(arg));
    return; 
}
template<typename Arg, typename ...Args>
void pass(Arg&& arg, Args&&... args)
{
    // use arg here
    return pass(std::forward<Args>(args)...);
}
int main(int, char**)
{
    pass(std::move<Test>(Test()));
    return 0;
}