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


when_any, return value

It seems more useful to add the ability to capture the return value from the first of the task functions to complete. Again, we assume that none will throw an exception.

One tactic would be to adapt our Done class to store the first of the return values, rather than a simple bool. However, we choose instead to use a buffered_channel<>. We'll only need to enqueue the first value, so we'll buffered_channel::close() it once we've retrieved that value. Subsequent push() calls will return closed.

// Assume that all passed functions have the same return type. The return type
// of wait_first_value() is the return type of the first passed function. It is
// simply invalid to pass NO functions.
template< typename Fn, typename ... Fns >
typename std::result_of< Fn() >::type
wait_first_value( Fn && function, Fns && ... functions) {
    typedef typename std::result_of< Fn() >::type return_t;
    typedef boost::fibers::buffered_channel< return_t > channel_t;
    auto chanp( std::make_shared< channel_t >( 64) );
    // launch all the relevant fibers
    wait_first_value_impl< return_t >( chanp,
                                       std::forward< Fn >( function),
                                       std::forward< Fns >( functions) ... );
    // retrieve the first value
    return_t value( chanp->value_pop() );
    // close the channel: no subsequent push() has to succeed
    return value;

The meat of the wait_first_value_impl() function is as you might expect:

template< typename T, typename Fn >
void wait_first_value_impl( std::shared_ptr< boost::fibers::buffered_channel< T > > chan,
                            Fn && function) {
    boost::fibers::fiber( [chan, function](){
                              // Ignore channel_op_status returned by push():
                              // might be closed; we simply don't care.
                              chan->push( function() );

It calls the passed function, pushes its return value and ignores the push() result. You might call it like this:

std::string result = wait_first_value(
        [](){ return sleeper("wfv_third",  150); },
        [](){ return sleeper("wfv_second", 100); },
        [](){ return sleeper("wfv_first",   50); });
std::cout << "wait_first_value() => " << result << std::endl;
assert(result == "wfv_first");