The C++ 11 std::future lacks a then method to attach continuations to the future.
The Boost boost::future provides this, and t
If you would prefer using std::future instead of boost::future, you could just use this:
#include
#include
#include
#include
namespace later {
// infix operator boilerplate:
template struct infix_tag {};
template
struct partial {
std::future&& lhs;
};
// note: moves lhs!
template
partial operator*( std::future& lhs, infix_tag ) {
return { std::move(lhs) };
}
template
partial operator*( std::future&& lhs, infix_tag ) {
return { std::move(lhs) };
}
template
struct continue_t;
template
std::future< typename continue_t::type >
operator*( partial&& lhs, RHS&& rhs )
{
return continue_t()( std::move(lhs.lhs), std::forward(rhs) );
}
// std::future *then* lambda(T) support:
struct then_t:infix_tag {};
static constexpr then_t then;
template
struct continue_t {
typedef typename std::result_of< RHS( LHS ) >::type type;
template
std::future operator()( std::future&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared>( std::move(lhs_) );
auto rhs = std::make_shared::type>( std::forward(rhs_) );
return std::async( [lhs, rhs]()->type { return (*rhs)((*lhs).get()); });
}
};
template
struct continue_t {
typedef typename std::result_of< RHS() >::type type;
template
std::future operator()( std::future&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared>( std::move(lhs_) );
auto rhs = std::make_shared::type>( std::forward(rhs_) );
return std::async( [lhs, rhs]()->type { lhs->get(); return (*rhs)(); });
}
};
// std::future *as_well* lambda() support:
struct as_well_t:infix_tag {};
static constexpr as_well_t as_well;
template
struct continue_t::type>::value>::type> {
typedef std::tuple< LHS, typename std::result_of< RHS() >::type> type;
template
std::future operator()( std::future&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared>( std::move(lhs_) );
auto rhs = std::make_shared::type>( std::forward(rhs_) );
return std::async( [lhs, rhs]()->type {
auto&& r = (*rhs)();
return std::make_tuple((*lhs).get(), std::forward(r));
});
}
};
template
struct continue_t::type>::value>::type> {
typedef LHS type;
template
std::future operator()( std::future&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared>( std::move(lhs_) );
auto rhs = std::make_shared::type>( std::forward(rhs_) );
return std::async( [lhs, rhs]()->type {
(*rhs)();
return (*lhs).get();
});
}
};
template
struct continue_t::type>::value>::type> {
typedef typename std::result_of< RHS() >::type type;
template
std::future operator()( std::future&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared>( std::move(lhs_) );
auto rhs = std::make_shared::type>( std::forward(rhs_) );
return std::async( [lhs, rhs]()->type {
auto&& r = (*rhs)();
lhs->get();
return std::forward(r);
});
}
};
template
struct continue_t::type>::value>::type> {
typedef typename std::result_of< RHS() >::type type;
template
std::future operator()( std::future&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared>( std::move(lhs_) );
auto rhs = std::make_shared::type>( std::forward(rhs_) );
return std::async( [lhs, rhs]()->type {
(*rhs)();
lhs->get();
return;
});
}
};
}
using later::then;
using later::as_well;
int main() {
std::future computation = std::async( [](){ return 7; })
*then* [](int x) { return x+2; }
*as_well* []() { std::cout << "step 2\n"; }
*then* [](int x) { std::cout << x << "\n"; return x; }
*as_well* []() { return 3; }
*then* []( std::tuple m ){ std::cout << std::get<0>(m) + std::get<1>(m) << "\n"; }
*as_well* []() { std::cout << "bah!\n"; return 3; };
computation.wait();
// your code goes here
return 0;
}
which is a little hacked together infix then library I just wrote.
It is far from perfect, because it does not continue the then task within the future: each then or as_well spawns a new task.
In addition, as_well doesn't merge tuples -- if the left hand side std::future is a std::future, I should merge with it, rather than make a std::tuple of std::tuples. Oh well, later revision can handle that.