Reputation: 2052
I want to use boost::promise::set_exception()
that expects a boost::exception_ptr
. The problem is that boost:exception_ptr
seems to work correctly only if I wrap all my throws with enable_current_exception
and I want to avoid that. (I wouldn't be able to do that for 3rd party libraries anyway.)
I use std::exception_ptr/std::current_exception
throughout my code, so I am looking for a way to pass std::exception_ptr
where a boost:exception_ptr
is expected.
Something that does the following, but compiles:
boost::exception_ptr convert(std::exception_ptr ex) {
try {
std::rethrow_exception(ex);
}
catch(auto& ex) {
try {
throw boost::enable_current_exception(ex);
}
catch (...) {
return boost::current_exception();
}
}
}
Do you have any idea how to do that?
Context:
I need boost::future::then()
, so using a std::promise
is unfortunately not an option (at least at the moment)
If you know a way to make boost::exception_ptr
to rely on gcc 4.8 compiler support instead of enable_current_exception
that would be an acceptable solution, as well
Upvotes: 8
Views: 2574
Reputation: 475
I found not the best solution, but it works.
namespace boost::exception_detail
{
template<>
class clone_impl< std::exception_ptr > : public clone_base
{
std::exception_ptr mExceptionPtr;
public:
clone_impl( std::exception_ptr exception_ptr )
: mExceptionPtr{ std::move( exception_ptr ) }
{
}
clone_base const* clone() const
{
return new clone_impl( *this );
}
void rethrow() const
{
std::rethrow_exception( mExceptionPtr );
}
};
int clone_current_exception_non_intrusive( clone_base const*& cloned )
{
cloned = new clone_impl< std::exception_ptr >{ std::current_exception() };
return clone_current_exception_result::success;
}
}
BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR
definitionUpvotes: 1
Reputation: 3989
Unfortunately, I don't think this is possible. However, I can offer you three possible solutions, sorted by convenience:
boost::exception_ptr convert(std::exception_ptr ex)
{
try {
std::rethrow_exception(ex);
} catch (const std::exception& e) {
try {
throw boost::enable_current_exception(e);
} catch (...) {
return boost::current_exception();
}
} catch (...) {
try {
throw boost::enable_current_exception(std::runtime_error("Unknown exception."));
} catch (...) {
return boost::current_exception();
}
}
}
int main()
{
std::exception_ptr sep;
try {
throw std::runtime_error("hello world");
} catch (...) {
sep = std::current_exception();
}
boost::exception_ptr bep = convert(sep);
try {
boost::rethrow_exception(bep);
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
}
This prints "std::exception"
instead of "hello world"
, since information from derived classes (in this case, std::runtime_error
) will be sliced away.
boost::exception_ptr convert(std::exception_ptr ex)
{
try {
throw boost::enable_current_exception(ex);
} catch (...) {
return boost::current_exception();
}
}
int main()
{
std::exception_ptr sep;
try {
throw std::runtime_error("hello world");
} catch (...) {
sep = std::current_exception();
}
boost::exception_ptr bep = convert(sep);
try {
boost::rethrow_exception(bep);
} catch (const std::exception_ptr& ep) {
try {
std::rethrow_exception(ep);
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
}
}
This version prints "hello world"
, albeit at the cost of an extra try
/catch
block. If error handling is done at a central location, maybe displaying a dialog box, I'd go for this solution. Until the boost authors add a constructor from std::exception_ptr
to boost::exception_ptr
, that's as good as it gets, I'm afraid.
If you can live with using packaged_task
, this solution works:
#define BOOST_THREAD_VERSION 4
#include <boost/thread.hpp>
int main()
{
boost::packaged_task<int()> pt([] () -> int {
throw std::runtime_error("hello world");
});
boost::future<int> f1 = pt.get_future();
boost::future<int> f2 = f1.then([] (boost::future<int> f) {
return f.get() + 1;
});
boost::thread(std::move(pt)).detach();
try {
int res = f2.get();
} catch (const std::runtime_error& e) {
std::cout << e.what() << std::endl;
}
}
Prints "hello world"
and allows you to use fut.then()
.
Upvotes: 3