C++ 模板 - 可变参数模板和通过 const 引用传递

C++ template - variadic templates & pass by const reference

我有一个 ThreadPool class 和 enqueue 函数:

class ThreadPool
{
public:
    //(Code removed here)

    template <typename ... Args, typename Fun>
    JobId enqueue(Fun func, Args ... args);

    //(Code removed here)
}

我在 class Object:

这些非静态成员函数 loadStuff 上使用它
class Object
{
    //(Code removed here)
    void init(const PrepareData & prepareData);
    virtual bool loadStuff(const PrepareData & prepareData);
    //(Code removed here)
}

通过调用 QObject::init :

void QObject::init(const PrepareData &prepareData)
{
    threadPool->enqueue(&loadStuff, this, prepareData);
}

但我注意到 prepareData 是通过副本传递的,这会消耗大量内存并显着降低程序速度(并且无用)。

所以我删除了PrepareData中的copy ctor和assignment operator。该程序不再编译,因为可变参数模板按值而非引用获取其参数。

所以我声明 enqueue 通过引用传递可变模板参数:

template <typename ... Args, typename Fun>
JobId enqueue(Fun func, Args&... args);

现在复制构造函数不再被调用,但出现以下错误:

object.cpp:21: error: no matching function for call to

'ThreadPool::enqueue(bool (Object::*)(const PrepareData&), Object *, const PrepareData&)' threadPool->enqueue(&prepareType, this, loadStuff);

所以我完全不知道该怎么做。我可以不传递 const PrepareData &,而是通过副本传递 const PrepareData *,但我想了解为什么它不适用于 const 引用。

这个:

template <typename ... Args, typename Fun>
JobId enqueue(Fun func, Args ... args);

复制所有 args 因为它们都是按值传递的。参数传递的工作方式似乎有些混乱——调用 enqueue 并引用 const 并不重要,重要的是 enqueue 按值获取其参数。 init() 通过引用传递,但 enqueue() 不是。

您可能想要的是将引用包装器传递给您的数据(按值):

threadPool->enqueue(&loadStuff, this, std::ref(prepareData));

这将避免复制 prepareData 并正确调用 loadStuff()。这也让 enqueue() 的调用者有责任知道应该复制哪些内容以及应该引用哪些内容。


虽然,QObject需要确保prepareData持续足够长的时间。我们通过引用 const 来获取它,所以它似乎没有任何方法可以做到这一点。因此,也许另一种方法是 init() 按值获取其数据:

void QObject::init(PrepareData prepareData)
{
    threadPool->enqueue(&loadStuff, this, std::move(prepareData));
}