Hook outcome
The final step is to add event hooks for the very specific case of
when our localised outcome
is copy or move constructed from our localised result
.
You ought to be very careful that the noexcept
-ness of these matches the noexcept
-ness
of the types in the outcome
. You may have noticed that poke_exception()
creates
a std::string
and appends to it. This can throw an exception. If the copy and/or
move constructors of T
, EC
and EP
are noexcept
, then so will be outcome
’s
copy and/or move constructor. Thus if poke_exception()
throws, instant program
termination would occur, which is bad.
We avoid that problem in this case by wrapping poke_exception()
in a try...catch
which throws away any exceptions thrown. For Outcome before v2.2, these specially
named free functions must be placed into a namespace which is ADL searched:
namespace error_code_extended
{
// Specialise the outcome copy and move conversion hook for when our localised result
// is used as the source for copy construction our localised outcome
template <class T, class U> inline void hook_outcome_copy_construction(outcome<T> *res, const result<U> & /*unused*/) noexcept
{
try
{
// when copy constructing from a result<T>, poke in an exception
poke_exception(res);
}
catch(...)
{
// Do nothing
}
}
template <class T, class U> inline void hook_outcome_move_construction(outcome<T> *res, result<U> && /*unused*/) noexcept
{
try
{
// when move constructing from a result<T>, poke in an exception
poke_exception(res);
}
catch(...)
{
// Do nothing
}
}
}
For Outcome v2.2 and later, these functions must be placed into a custom no value
policy with the names on_outcome_copy_construction()
and on_outcome_move_construction()
respectively. As with before, the implementation of the functions is identical, just
the name and location has changed.