I am playing with an example 4.14 from the book Antony Williams - C + + Concurrency in Action in which emulated std::async using std::packaged_task and std::thread.
Why this code does not compile when I uncomment lines and how to rewrite template to make it work?
#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;
}
Compilation errors:
nnovzver@archer /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.
If you look at the documentation of async, the feature you want to emulate, it decays all the future template arguments. And it is effective as it works far better like this, as show 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;
}