2016-06-09 123 views
1

我有一個ThreadPool類的enqueue功能:C++模板 - 可變參數模板和路過常引用

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

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

    //(Code removed here) 
} 

我用它在這些非靜態成員函數loadStuffObject類:

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和賦值操作符。該程序不再編譯,因爲可變參數模板通過值而不是參考來獲取參數。

因此,我宣佈排隊按引用傳遞的可變參數模板參數:

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引用。

+0

說'參數數量&& ...'。 –

回答

1

此:

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

複製所有args,因爲他們都按值傳遞。對於參數傳遞如何工作似乎存在一些混淆 - 無論您是否在調用const時引用enqueue都沒關係,重要的是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)); 
} 
+0

發送到線程池*的東西默認情況下應爲*值,以避免生命期問題。如果OP需要引用語義,他們可以使用'reference_wrapper'。 –

+0

@ T.C。好點,沒有考慮'enqueue()'在做什麼。 – Barry

+0

@ T.C。 :我理解你的擔心,但是這裏的PrepareData是一堆大的const數據集,應該不會被複制。我確保它保持在那裏,直到所有的線程池函數保持爲止,實際上threadPool和prepareData是一個更大類的兩個成員,它確保了這一點。 – galinette