2014-03-28 29 views
3

我正在玩一個例子4.14從Antony Williams - C++ Concurrency in Action中使用std :: packaged_task和std :: thread來模擬std :: async。帶有封裝任務的模板不能編譯

爲什麼當我取消註釋行以及如何重寫模板以使其工作時,此代碼無法編譯?

#include <iostream> 
#include <future> 
#include <thread> 
#include <string> 

void func_string(const std::string &x) {} 

void func_int(int x) {} 

template <typename F, typename A> 
std::future<typename std::result_of<F(A&&)>::type> spawn_task(F &&f, A &&a) { 
    typedef typename std::result_of<F(A&&)>::type result_type; 
    std::packaged_task<result_type(A&&)> task(std::move(f)); 
    std::future<result_type> res(task.get_future()); 
    std::thread t(std::move(task), std::move(a)); 
    t.detach(); 
    return res; 
} 


int main() { 
    std::string str = "abc"; 

    // auto res1 = spawn_task(func_string, str); 
    // res1.get(); 
    auto res2 = spawn_task(func_int, 10); 
    res2.get(); 

    return 0; 
} 

編譯錯誤:

[email protected] /tmp $ clang++ -std=c++11 -lpthread temp.cpp && ./a.out 
In file included from temp.cpp:2: 
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/future:38: 
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1697:56: error: no type 
     named 'type' in 'std::result_of<std::packaged_task<void (std::basic_string<char> &)> (std::basic_string<char>)>' 
     typedef typename result_of<_Callable(_Args...)>::type result_type; 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ 
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:135:41: note: in instantiation 
     of template class 'std::_Bind_simple<std::packaged_task<void (std::basic_string<char> &)> 
     (std::basic_string<char>)>' requested here 
     _M_start_thread(_M_make_routine(std::__bind_simple(
             ^
temp.cpp:15:15: note: in instantiation of function template specialization 'std::thread::thread<std::packaged_task<void 
     (std::basic_string<char> &)>, std::basic_string<char> >' requested here 
    std::thread t(std::move(task), std::move(a)); 
      ^
temp.cpp:24:15: note: in instantiation of function template specialization 'spawn_task<void (&)(const 
     std::basic_string<char> &), std::basic_string<char> &>' requested here 
    auto res1 = spawn_task(func_string, str); 
      ^
In file included from temp.cpp:2: 
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/future:38: 
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1726:50: error: no type 
     named 'type' in 'std::result_of<std::packaged_task<void (std::basic_string<char> &)> (std::basic_string<char>)>' 
     typename result_of<_Callable(_Args...)>::type 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ 
2 errors generated. 
+1

你能否提供編譯錯誤? – Chnossos

+0

@Chnossos新增 – nnovzver

+0

編譯的工作原理如下:'void func_string(std :: string && x)'並使用'std :: move(str)'。我仍然不確定如何處理在一般情況下適當完美的轉發... – galop1n

回答

1

如果你看一下異步的documentation,你想模仿的特性,它衰變所有的未來模板參數。它是有效的,因爲它的效果好得多,如下所示:here

template <typename T_> 
using decay_t = typename std::decay<T_>::type; 
template< class T > 
using result_of_t = typename std::result_of<T>::type; 

template <typename F, typename A> 
std::future<result_of_t<decay_t<F>(decay_t<A>)>> spawn_task(F &&f, A &&a) { 
    using result_t = result_of_t<decay_t<F>(decay_t<A>)>; 
    std::packaged_task< result_t(decay_t<A>)> task(std::forward<F>(f)); 
    auto res = task.get_future(); 
    std::thread t(std::move(task), std::forward<A>(a)); 
    t.detach(); 
    return res; 
} 
+0

太好了,謝謝! ) – nnovzver

+0

我實際上在一行中做了一個修改,它運行了'std :: packaged_task )> task(std :: move(f));'。沒有'std :: forward'這本書的例子也是無用的。 – nnovzver

+1

@novzver'std :: move'是不好的,因爲如果你傳遞一個非rvalue元素,你將會從它移動。這是非常粗魯的。 – Yakk

1

所有std::packaged_task首先包裹任何可贖回目標函數。 Callable的其中一個要求是它具有合適的返回值。 void不是合適的返回值。我改變了你的函數返回int用於測試目的:

int func_string(const std::string &x) 
{ 
    return 1; 
} 

int func_int(int x) 
{ 
    return 2; 
} 

其次,它看起來像你對我有你的實際功能的簽名和您指定的std::result_of<>什麼模板之間的不匹配。特別是你的函數簽名是:

int func_string(const std::string &x); 
int func_int(int x); 

但你逝去:

std::result_of<F(A&&)>::type result_type 

改變,爲:

std::result_of<F(A)>::type result_type 

所有的一切都編譯。

以下是完整的源代碼(減去頭):

int func_string(const std::string &x) 
{ 
    return 1; 
} 

int func_int(int x) 
{ 
    return 2; 
} 

template <typename F, typename A> 
std::future<typename std::result_of<F(A)>::type> spawn_task(F &&f, A &&a) 
{ 
    typedef typename std::result_of<F(A)>::type result_type; 
    std::packaged_task<result_type(A)> task(std::move(f)); 
    std::future<result_type> res(task.get_future()); 
    std::thread t(std::move(task), std::move(a)); 
    t.detach(); 
    return res; 
} 

int main() 
{ 
    std::string str = "abc"; 

    auto res1 = spawn_task(func_string, str); 
    res1.get(); 
    auto res2 = spawn_task(func_int, 10); 
    res2.get(); 
} 
+1

這不要etheir:http://coliru.stacked-crooked.com/a/27e5d630470f5e4c – galop1n

+0

@ galop1n有趣的 - 這編譯和正確運行VS2013。 –

+2

永遠不要相信VS編譯器...... – galop1n