Using boost::future with “then” continuations

后端 未结 4 1563
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-24 12:35

The C++ 11 std::future lacks a then method to attach continuations to the future.

The Boost boost::future provides this, and t

4条回答
  •  滥情空心
    2020-12-24 13:22

    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.

提交回复
热议问题