我有一个带有 enqueue
函数的 ThreadPool
类:
class ThreadPool
{
public:
//(Code removed here)
template <typename ... Args, typename Fun>
JobId enqueue(Fun func, Args ... args);
//(Code removed here)
}
我在 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
接受它的参数按值(value)。 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));
}
关于C++ 模板 - 可变参数模板和通过 const 引用传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37730989/