Using std::async
I was wondering whether it is possible to have a helper function, which creates std::future
s from a collection (one future for every collection element).
Often I have the following situation:
auto func = []( decltype(collection)::reference value ) {
//Some async work
};
typedef std::result_of<decltype(func)>::type ResultType;
std::vector<std::future<ResultType>> futures;
futures.reserve(collection.size());
// Create all futures
for( auto& element : collection ) {
futures.push_back(std::async(func, element));
}
// Wait till futures are done
for( auto& future : futures ) {
future.wait();
}
To be able to easily reuse this I came up with the following partial code:
template< class Function, class CT, class... Args>
std::vector<std::future<typename std::result_of<Function(Args...)>::type>>
async_all( Function&& f, CT& col ) {
typedef typename std::result_of<Function(Args...)>::type ResultType;
std::vector<std::future<ResultType>> futures;
futures.reserve(collection.size());
for( auto& element : collection ) {
futures.push_back(std::async(func, element));
}
}
return futures;
Now I have to solve the Args
problem, since in async_all
, Args
cannot be deduced anymore. The only thing I currently can think of is another functor, which converts an element in collection to Args
.
Is there any more elegant solution to this?
You're almost there. The collection passed to
async_all
has all the information we need to uniquely determine the function argument type; the only question is how to extract this information. Using theauto
keyword in the function signature, we can write the return type after the function arguments. This not only produces a cleaner signature, but also lets us use the argument values themselves together withdecltype
in deducing return types. For instance:Of course, there are other ways to determine argument types for provided functions (using function signature deduction with templates). However, these approaches can fail for cases involving overloaded functions and/or templated function objects.
The following code compiles and runs properly (prints "x=1" 10 times) under gcc 4.8 (earlier versions should work just fine). Notice how we don't even have to explicitly mention
std::future
: we can use decltype directly on thestd::async
statement to deduce it's type.(
async_all
is evaluated just once here, as the spec guarantees for range expressions in range-based for loops)