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
Unfortunately, I don't think this is possible. However, I can offer you three possible solutions, sorted by convenience:
1. Catch a std::exception
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.
2. Throw the std::exception_ptr directly
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.
Use boost::packaged_task instead of boost::promise
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()
.