将具有可变参数模板参数的成员函数传递给可变参数构造函数

Passing member functions with variadic template arguments to variadic constructors

本文关键字:参数 变参 函数 构造函数 成员      更新时间:2023-10-16

我不知道如何将带有可变参数模板参数的成员函数传递给std::thread构造函数。我有一个接收函数及其参数的方法,需要将它们传递给在新线程中调用并在那里调用传递函数的其他方法。这是简化版本:

class Test
{
public:
    template<typename Function, typename... Args>
    void Run(Function&& f, Args&&... args)
    {
        std::thread t(&Test::Operation, this, f, args...); // how???
        t.detach();
    }
    template<typename Function, typename... Args>
    void Operation(Function&& f, Args&&... args)
    {
        f(args...);
    }
};
Test test;
test.Run([](const std::string& msg) { std::cout << msg; }, "Hi!");

以这种方式传递参数有问题,我收到以下错误:"std::thread::thread":没有重载函数需要 4 个参数。我该怎么做?

这里的问题是,当您将&Test::Operation传递给线程构造函数时,它无法推断出&Test::Operation的模板参数。(如果你想了解为什么不能进行这种推论,你可能应该问一个单独的问题。关键是您需要显式指定 &Test::Operation 的模板参数。

这将看起来像这样:

template<typename Function, typename... Args>
void Run(Function&& f, Args&&... args)
{
    std::thread t(&Test::Operation<std::decay_t<Function>, std::decay_t<Args>...>,
                  this, std::forward<Function>(f), std::forward<Args>(args)...);
    t.detach();
}

我为您添加了完美的转发:这很重要,因为您不想执行不必要的复制,对吧?

但是为什么我们需要decay_t?这是因为线程构造函数在将参数的副本存储在新线程的内部存储中之前会衰减其参数,因此,例如,如果您传入"Hi!",则推导的类型是 const char (&)[4] ,但一旦衰减就会变成const char*,并且衰减是不可逆的,所以Test::Operation一定不要期待const char (&)[4], 无法从衰减的const char*初始化.因此,必须指定Test::Operation才能采用衰减类型。

您可能还希望在实际调用期间进行完美转发。

链接: http://coliru.stacked-crooked.com/a/c9d04c03a3758b51