N3865 More Improvements to std::future<T>
C++14後のConcurrency TSに予定されているfuture APIの改善では、std::future
にthen()
というメンバ関数を追加し、非同期処理を連続的に記述できるようにしよう、という案が出ています。
今回のこの提案文書は、Boost.Thread作者のVicenteさんによって提案されたもので(つまりfuture API改善を最初に実装する人)、then()
が使いにくいのでもう少しなんとかしよう、というものです。
future::then()
は引数として、future<T>
を受け取る関数をとります。
int main() { future<std::string> result = async([] { return 123; }) .then([](future<int> f) { return to_string(f.get()) + "hoge"; }) .then([](future<string> f) { return f.get() + "fuga"; }); std::cout << result.get() << std::endl; // 123hogefuga }
then()
で登録した関数はfuture
の準備ができたら呼ばれるので、登録した関数の中であらためてfuture
の完了を待つ必要はありません。
ではなぜfuture
が渡されるのかと言うと、それはfuture
が正常な値の他に、エラー(例外)も同時に扱うからです。using future = variant<T, exception_ptr>;
のようになってると思ってください。
つまり、then()
で登録した関数の中で、正常かエラーかを判断して適切に処理しなさい、という設計になっています。
前置きが長くなりましたが、今回の提案では、既存の提案にあるthen()
に加えて、next()
/recover()
というメンバ関数を追加することが考えられています。
int main() { future<std::string> result = async([] { return 123; }) .next([](int x) { return to_string(x) + "hoge"; }) .next([](string s) { return s + "fuga"; }); std::cout << result.get() << std::endl; // 123hogefuga }
next()
には、future<T>
ではなくT
を受け取る関数を登録します。エラーになったときのハンドリングには、next()
に続いて、recover()
を登録します。
int main() { future<std::string> result = async([] { return 123; }) .next([](int x) { return to_string(x) + "hoge"; }) .recover([](exception_ptr) { std::cout << “error” << std::endl; }); }
正常値の場合はnext()
に登録した関数が呼ばれ、エラーの場合はrecover()
に登録した関数が呼ばれます。
future
に格納する値は多くの場合に正常値なので、エラーのために毎回future<T>
を書くのを避けられるのはとても重要なポイントだと思います。
この提案ではその他にも、細かい改善のAPIが考えられています。
参照