#ifndef TEST_THREAD_WITH_EXCEPTIONS_H_ #define TEST_THREAD_WITH_EXCEPTIONS_H_ #include "exception_transporter.h" #include namespace test { namespace detail { struct throw_ : boost::static_visitor<> { template void operator()(const T& t) const { throw t; } }; } template struct thread_with_exceptions { template thread_with_exceptions(Fun f) : thread(transporter_wrapper(f, result)) { } Result join() { thread.join(); return boost::mpl::if_< boost::is_same, void_return, non_void_return>::type::return_(*result); } typedef exception_transporter transporter; typedef typename transporter::result_type result_type; private: struct transporter_wrapper { transporter_wrapper( boost::function f_, boost::optional& result_) : f(f_), result(result_) { } void operator()() { result.reset(transporter(f)()); } private: boost::function f; boost::optional& result; }; struct void_return { static void return_(const result_type& result) { if(result) { boost::apply_visitor(detail::throw_(), *result); assert(0); } } }; struct non_void_return { static Result return_(const result_type& result) { return boost::apply_visitor(local_visitor(), result); } private: struct local_visitor : boost::static_visitor { Result operator()(const Result& r) const { return r; } Result operator()( const typename transporter::exception_variant_type& exceptions) const { boost::apply_visitor(detail::throw_(), exceptions); //shouldn't be able to get here. //this is to avoid warning throw 0; } }; }; boost::optional result; boost::thread thread; }; } #endif /* TEST_THREAD_WITH_EXCEPTIONS_H_ */