Полезнее добавить возможность улавливания возвращаемого значения с первой из выполняемых функций задачи. Опять же, мы предполагаем, что никто не будет делать исключения.
Одной из тактик является адаптация нашего класса<Done
>для хранения первого из значений возврата, а не простого<bool
>. Вместо этого мы используем.<unbounded_channel<>
>. Нам нужно только заложить первое значение, поэтому мы<unbounded_channel::close()
>Как только мы получим это значение. Последующие<push()
>звонки вернутся<closed
>.
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 >() );
wait_first_value_impl< return_t >( channelp,
std::forward< Fn >( function),
std::forward< Fns >( functions) ... );
return_t value( channelp->value_pop() );
channelp->close();
return value;
}
Мясо функции<wait_first_value_impl()
>, как вы могли бы ожидать:
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](){
channel->push( function() );
}).detach();
}
Он называет пройденную функцию, толкает ее обратное значение и игнорирует результат<push()
>. Вы можете назвать это так:
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");