2015-10-14 134 views
1

我只是試圖爲給定的std::bind創建std::packaged_taskC++創建std :: packaged_task的通用std :: bind

#include <functional> 
#include <future> 

class A 
{ 
public: 
    template<class T> 
    void execute(T func) 
    { 
    std::packaged_task<T> task(func); 
    } 
}; 

int main() 
{ 
    auto func = std::bind([](int x) { return x*x; }, 5); 

    A name; 

    name.execute(func); 
} 

main.cpp: In instantiation of 'void A::execute(T) [with T = std::_Bind(int)>]': main.cpp:20:20: required from here main.cpp:10:36: error: 'std::packaged_task(int)> > task' has incomplete type std::packaged_task task(func);

我使用G ++ 5.2.0,和C++ 14。

有人有想法嗎?

謝謝

+0

'func'應該如何調用?如果有的話,它應該返回什麼? –

+0

'auto'在參數聲明中是不允許的。 – 0x499602D2

+0

問題是,它不能編譯 –

回答

3

爲C++ 11則無法聲明函數參數作爲汽車的(我相信C++ 17的一部分)。不幸的是,我沒有支持該功能編譯器,我不能肯定它的語義,但一個解決方法是使用模板:

#include <future> 
#include <functional> 

template<class T> 
void execute(std::function<T> func) // is a std::bind 
{ 
    std::packaged_task<T> task(func); 
    //... 
} 

您可以使用這樣的:

std::function<int()> func = std::bind([](int x) { return x*x; }, 5); 
execute(func); 

爲什麼出現此錯誤的問題是std::packaged_task僅專門用於ReturnType(Args...)格式的模板參數。所以如果你傳遞一些不同的東西,如std::_Binderstd::bindstd::function返回它看起來沒有定義。

編輯

關於你關於演繹性病的種類::功能註釋:

而不是使用std::bind()你可以使用lambda表達式。

如果你有一個類A與功能doSomething(int x)像您的評論:

class A 
{ 
public: 
    int doSomething(int x) 
    { 
     return x *x; 
    } 
}; 

我們需要改變執行功能以下(見Yakk的答案):

template<class F, class...Args> 
void execute(F&& func, Args&&...args) 
{ 
    using zF = std::decay_t<F>&&; 
    using R = std::result_of_t< zF(Args...) >; 
    std::packaged_task<R()> task(
     std::bind([func = std::forward<F>(func)](auto&&...args)mutable->R{ 
     return std::move(func)(decltype(args)(args)...); 
    }, std::forward<Args>(args)...) 
     ); 
} 

現在你可以這樣使用它:

A a; 

auto f = [](A& inst, int x) { return inst.doSomething(x); }; 
execute(f, a, 5); 

// or 

auto g = [&]() { return a.doSomething(5); }; 
execute(g); 

注意事項

請注意a的生命期,因爲packaged_task可能異步運行。

+0

恐怕這樣不能編譯, main.cpp:10:3​​6:error:'std :: packaged_task (int)>> task'has incomplete typestd :: packaged_task task(func); –

+0

但這正是這個想法以及問題來自何處。 –

+0

哦,我當然了,你必須包括標題。編輯我的帖子 –

1

這裏有一個簡單的解決方案:

template<class...Args, class F> 
void execute(F&& func) 
{ 
    using R = std::result_of_t< std::decay_t<F>(Args...) >; 
    std::packaged_task<R(Args...)> task(std::forward<F>(func)); 
} 

我加了完美轉發,並在參數傳遞的選項。如果你沒有傳入參數,它假定傳入的可調參數需要0個參數。

使用例:

auto func = std::bind([](int x) { return x*x; }, 5); 
A name; 
name.execute(func); 

如果func需要參數,你必須明確地傳遞它們。這只是公平的,因爲在不知道它會期待什麼爭論的情況下很難使用std::packaged_task。;)

這也編譯:

auto func = [](int x) { return x*x; }; 
A name; 
name.execute<int>(func); 

,但你將如何使用該包裝的任務是棘手。

如果你想模仿std::async之類的接口,我們可以這樣做:

template<class F, class...Args> 
void execute(F&& func, Args&&...args) 
{ 
    using zF = std::decay_t<F>&&; 
    using R = std::result_of_t< zF(Args...) >; 
    std::packaged_task<R()> task(
    std::bind([func=std::forward<F>(func)](auto&&...args)mutable->R{ 
     return std::move(func)(decltype(args)(args)...); 
    }, std::forward<Args>(args)...) 
); 
} 

它仔細包裹傳遞func在拉姆達以避免呼籲bindbind,然後結合參數傳入

現在,您可以:

name.execute([](int x){ return x*x; }, 5); 

不使用bind

上面的代碼尚未編譯,可能包含tpyos。