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));
}
我有一个 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));
}