Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of Boost. Click here to view this page for the latest version.
PrevUpHomeNext

Success/Error Virtual Methods

One classic approach to completion notification is to define an abstract base class with success() and error() methods. Code wishing to perform async I/O must derive a subclass, override each of these methods and pass the async operation a pointer to a subclass instance. The abstract base class might look like this:

// every async operation receives a subclass instance of this abstract base
// class through which to communicate its result
struct Response {
    typedef std::shared_ptr< Response > ptr;

    // called if the operation succeeds
    virtual void success( std::string const& data) = 0;

    // called if the operation fails
    virtual void error( AsyncAPIBase::errorcode ec) = 0;
};

Now the AsyncAPI operation might look more like this:

// derive Response subclass, instantiate, pass Response::ptr
void init_read( Response::ptr);

We can address this by writing a one-size-fits-all PromiseResponse:

class PromiseResponse: public Response {
public:
    // called if the operation succeeds
    virtual void success( std::string const& data) {
        promise_.set_value( data);
    }

    // called if the operation fails
    virtual void error( AsyncAPIBase::errorcode ec) {
        promise_.set_exception(
                std::make_exception_ptr(
                    make_exception("read", ec) ) );
    }

    boost::fibers::future< std::string > get_future() {
        return promise_.get_future();
    }

private:
    boost::fibers::promise< std::string >   promise_;
};

Now we can simply obtain the future<> from that PromiseResponse and wait on its get():

std::string read( AsyncAPI & api) {
    // Because init_read() requires a shared_ptr, we must allocate our
    // ResponsePromise on the heap, even though we know its lifespan.
    auto promisep( std::make_shared< PromiseResponse >() );
    boost::fibers::future< std::string > future( promisep->get_future() );
    // Both 'promisep' and 'future' will survive until our lambda has been
    // called.
    api.init_read( promisep);
    return future.get();
}

The source code above is found in adapt_callbacks.cpp and adapt_method_calls.cpp.


PrevUpHomeNext