完美转发const ref推导错误

时间:2019-02-14 15:42:05

标签: c++ c++17 perfect-forwarding

我编写了一个超级简单的线程包装器,该包装器具有一个函数并将其运行在线程中,并提供了一种简单的机制来在需要退出时向线程发出信号。启动功能看起来像

//tw.hpp

class ThreadWrapper
{
public:
  // ...snipped ...
  template<typename... Args>
  bool start(Args&& ... args)
  {
    ft_ = std::async(std::launch::async, std::forward<Args>(args)...  );
    return true;
  }
};

当我将其用于非成员函数时,我需要将包装器的const ref传递到正在运行的函数中,以提供一个该函数可用来知道何时退出的句柄:

void lone_worker(const ThreadWrapper& tw)
{
  while (!tw.is_quit_requested())
  {
    std::cout << "working hard alone\n";
    sleep(1);
  }
}

void nonmember_demo()
{
  ThreadWrapper tw;
  tw.start(&lone_worker, std::cref(tw)); // the cref is need to avoid hundreds of lines of compiler template puke with no useful error messages
  sleep(5);
  std::cout << "quitting\n";
  tw.request_quit();
}

我最初不使用std::cref进行编译时就措手不及,实际上是数百行编译器模板puke(gcc 8.1.0)并没有明确的原因。是否有某些我需要完善的转发功能才能使用cref的功能?我认为部分原因是该类不可复制(它包含一个std :: future),这种气味有点儿,因为至少我认为一开始就不应复制任何内容。 完整示例如下:https://coliru.stacked-crooked.com/a/0eb4d6160b44764a

1 个答案:

答案 0 :(得分:1)

  

闻起来有点香,因为至少我认为一开始就不应该复制任何内容

您假设错误。 async主要只是转发到thread,其开始于执行:

std::invoke(decay_copy(std::forward<Function>(f)), 
            decay_copy(std::forward<Args>(args))...);

这确实复制了所有参数。参考包装的重点是避免这种复制-您正在复制ThreadWrapper(可复制),而不是复制std::reference_wrapper<ThreadWrapper const>对象(不可复制)。

从链接的thread的cppreference页面中:

  

线程函数的参数按值移动或复制。如果需要将引用参数传递给线程函数,则必须将其包装(例如,使用std::refstd::cref)。