C++ 11 _std::future
_ lacks 将来に継続をアタッチするthen
メソッド。
ブースト_boost::future
_ 提供する これ、そして 例 があります(これは実行できません)
私は単にコンパイルできません:
_#include <iostream>
#include <string>
#include <boost/thread/future.hpp>
boost::future<int> join2(const std::string& realm) {
boost::promise<int> p;
p.set_value(23);
return p.get_future();
}
int main () {
boost::future<int> f = join2("realm1");
// here, I'd like to use f.then(..)
f.wait();
std::cout << f.get() << std::endl;
}
_
コンパイル時
_clang++ -o test5.o -c -std=c++11 -stdlib=libc++ \
-I/home/oberstet/boost_1_55_0 test5.cpp
_
これは
_test5.cpp:30:1: error: unknown type name 'future'
future<int> join(const std::string& realm) {
...
_
私は愚かだ;)何が起こっているのですか?私はclang 3.4をlibc ++とBoost 1.55で使用しています(Boost Webサイトの未変更のバニラソース)。
ヒントを得るのは素晴らしいでしょう。おそらく.then(..)
を使用して例を変更し、結果を出力する方法の例も示します。
ソリューション(kudos @dyp):
_#define BOOST_THREAD_PROVIDES_FUTURE
#include <boost/thread/future.hpp>
_
c ++ 11(futureを提供する)向けにコンパイルする場合は必須と思われますが、それでもBoost futureを使用したいと考えています。
実際に継続を使用するには、別の定義が必要です:_BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
_。
ここに完全な例があります
_#include <iostream>
#include <string>
#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#include <boost/thread/future.hpp>
using namespace boost;
int main() {
future<int> f1 = async([]() { return 123; });
future<std::string> f2 = f1.then([](future<int> f) {
std::cout << f.get() << std::endl; // here .get() won't block
return std::string("sgfsdfs");
});
}
_
Boost.Threadにはいくつかのバージョンがあり、BOOST_THREAD_VERSION
マクロで選択できます。現在、デフォルトは2
です。
Boost.Threadのバージョン2までは、このクラステンプレートにboost::unique_future
という名前が使用されていました(boost::shared_future
と比較してください)。おそらくstd::future
の標準化により、より最近のバージョンcanはboost::future
という名前を使用します。バージョン3
以降、boost::future
がデフォルト名です。
使用する名前の選択は、プリプロセッサマクロを介して行われます。
BOOST_THREAD_VERSION==2
を使用する場合は、BOOST_THREAD_PROVIDES_FUTURE
を定義してboost::future
を定義します。BOOST_THREAD_VERSION>=3
を使用する場合は、BOOST_THREAD_DONT_PROVIDE_FUTURE
を定義してboost::unique_future
を定義します。
From boost docs:unique_future
vs future
したがって、boost::future
を使用してBOOST_THREAD_PROVIDES_FUTURE
を明示的に有効にするか、たとえばBOOST_THREAD_VERSION
を4
に設定して、Boost.Threadのより新しいバージョンに切り替えることができます。
std::future
の代わりにboost::future
を使用したい場合は、 これを使用 :
#include <iostream>
#include <thread>
#include <future>
#include <memory>
namespace later {
// infix operator boilerplate:
template<typename T> struct infix_tag {};
template<typename op, typename LHS>
struct partial {
std::future<LHS>&& lhs;
};
// note: moves lhs!
template<typename LHS, typename Op>
partial<Op, LHS> operator*( std::future<LHS>& lhs, infix_tag<Op> ) {
return { std::move(lhs) };
}
template<typename Op, typename LHS>
partial<Op, LHS> operator*( std::future<LHS>&& lhs, infix_tag<Op> ) {
return { std::move(lhs) };
}
template<typename Op, typename LHS, typename RHS, typename=void>
struct continue_t;
template<typename Op, typename LHS, typename RHS>
std::future< typename continue_t<Op, LHS, RHS>::type >
operator*( partial<Op, LHS>&& lhs, RHS&& rhs )
{
return continue_t<Op, LHS, RHS>()( std::move(lhs.lhs), std::forward<RHS>(rhs) );
}
// std::future<T> *then* lambda(T) support:
struct then_t:infix_tag<then_t> {};
static constexpr then_t then;
template<typename LHS, typename RHS>
struct continue_t<then_t, LHS, RHS, void> {
typedef typename std::result_of< RHS( LHS ) >::type type;
template<typename T, typename U>
std::future<type> operator()( std::future<T>&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared<std::future<T>>( std::move(lhs_) );
auto rhs = std::make_shared<typename std::remove_reference<U>::type>( std::forward<U>(rhs_) );
return std::async( [lhs, rhs]()->type { return (*rhs)((*lhs).get()); });
}
};
template<typename RHS>
struct continue_t<then_t, void, RHS, void> {
typedef typename std::result_of< RHS() >::type type;
template<typename T, typename U>
std::future<type> operator()( std::future<T>&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared<std::future<T>>( std::move(lhs_) );
auto rhs = std::make_shared<typename std::remove_reference<U>::type>( std::forward<U>(rhs_) );
return std::async( [lhs, rhs]()->type { lhs->get(); return (*rhs)(); });
}
};
// std::future<T> *as_well* lambda() support:
struct as_well_t:infix_tag<as_well_t> {};
static constexpr as_well_t as_well;
template<typename LHS, typename RHS>
struct continue_t<as_well_t, LHS, RHS, typename std::enable_if<!std::is_same<void, typename std::result_of< RHS() >::type>::value>::type> {
typedef std::Tuple< LHS, typename std::result_of< RHS() >::type> type;
template<typename T, typename U>
std::future<type> operator()( std::future<T>&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared<std::future<T>>( std::move(lhs_) );
auto rhs = std::make_shared<typename std::remove_reference<U>::type>( std::forward<U>(rhs_) );
return std::async( [lhs, rhs]()->type {
auto&& r = (*rhs)();
return std::make_Tuple((*lhs).get(), std::forward<decltype(r)>(r));
});
}
};
template<typename LHS, typename RHS>
struct continue_t<as_well_t, LHS, RHS, typename std::enable_if<std::is_same<void, typename std::result_of< RHS() >::type>::value>::type> {
typedef LHS type;
template<typename T, typename U>
std::future<type> operator()( std::future<T>&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared<std::future<T>>( std::move(lhs_) );
auto rhs = std::make_shared<typename std::remove_reference<U>::type>( std::forward<U>(rhs_) );
return std::async( [lhs, rhs]()->type {
(*rhs)();
return (*lhs).get();
});
}
};
template<typename RHS>
struct continue_t<as_well_t, void, RHS, typename std::enable_if<!std::is_same<void, typename std::result_of< RHS() >::type>::value>::type> {
typedef typename std::result_of< RHS() >::type type;
template<typename T, typename U>
std::future<type> operator()( std::future<T>&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared<std::future<T>>( std::move(lhs_) );
auto rhs = std::make_shared<typename std::remove_reference<U>::type>( std::forward<U>(rhs_) );
return std::async( [lhs, rhs]()->type {
auto&& r = (*rhs)();
lhs->get();
return std::forward<decltype(r)>(r);
});
}
};
template<typename RHS>
struct continue_t<as_well_t, void, RHS, typename std::enable_if<std::is_same<void, typename std::result_of< RHS() >::type>::value>::type> {
typedef typename std::result_of< RHS() >::type type;
template<typename T, typename U>
std::future<type> operator()( std::future<T>&& lhs_, U&& rhs_ ) const {
auto lhs = std::make_shared<std::future<T>>( std::move(lhs_) );
auto rhs = std::make_shared<typename std::remove_reference<U>::type>( std::forward<U>(rhs_) );
return std::async( [lhs, rhs]()->type {
(*rhs)();
lhs->get();
return;
});
}
};
}
using later::then;
using later::as_well;
int main() {
std::future<int> computation = std::async( [](){ return 7; })
*then* [](int x) { return x+2; }
*as_well* []() { std::cout << "step 2\n"; }
*then* [](int x) { std::cout << x << "\n"; return x; }
*as_well* []() { return 3; }
*then* []( std::Tuple<int, int> m ){ std::cout << std::get<0>(m) + std::get<1>(m) << "\n"; }
*as_well* []() { std::cout << "bah!\n"; return 3; };
computation.wait();
// your code goes here
return 0;
}
これは少しハッキングされたインフィックス、次にライブラリです。
then
内でfuture
タスクを継続しないため、完全ではありません。各then
またはas_well
は新しいタスクを生成します。
さらに、as_well
はTuple
sをマージしません-左側のstd::future
がstd::future<std::Tuple<blah, blah>>
の場合、std::Tuple
をstd::Tuple
sにするのではなく、マージする必要があります。まあ、それ以降のリビジョンはそれを処理できます。
このマクロの定義は、非常に小さな些細なプログラムではうまくいくようですが、大きなプログラムではうまくいきません。特に、インクルードパス内の他のファイルには、偶発的にboost/thread.hppまたはboost/thread/future.hppが含まれる場合があります。これは、サードパーティのライブラリに含まれている場合でも発生します。その結果、マクロが定義される前にヘッダーが含まれるようになるため、マクロの使用が中断されます。この問題を回避できるように、ブーストをビルドして、これらのマクロをconfig.hppファイルの1つに定義するようにブーストを指示する方法はありますか?