| Home | Libraries | People | FAQ | More

#### 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 `unbounded_channel<>`. We'll only need to enqueue the first value, so we'll `unbounded_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::unbounded_channel< return_t > channel_t;
        auto channelp( std::make_shared< channel_t >() );
        // launch all the relevant fibers
        wait_first_value_impl< return_t >( channelp,
                                           std::forward< Fn >( function),
                                           std::forward< Fns >( functions) ... );
        // retrieve the first value
        return_t value( channelp->value_pop() );
        // close the channel: no subsequent push() has to succeed
        channelp->close();
        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::unbounded_channel< T > > channel,
                                Fn && function) {
        boost::fibers::fiber( [channel, function](){
                                  // Ignore channel_op_status returned by push():
                                  // might be closed; we simply don't care.
                                  channel->push( function() );
                              }).detach();
    }

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");