Hooking events

Outcome provides multiple methods for user code to intercept various lifecycle events which occur. The deepest method is simply to inherit from basic_result or basic_outcome, and override member functions, for which you will need to study the source code as that form of customisation is out of scope for this tutorial.

Another option is to supply a custom NoValuePolicy (see preceding section). From Outcome v2.2 onwards, intercepting construction, copies and moves requires a custom NoValuePolicy.

Before Outcome v2.2, there was an ADL discovered event hook mechanism for intercepting construction, copies and moves (it was found to be brittle, error prone and surprising in empirical use, which is why it was replaced). The ADL discovered event hooks still function in Outcome v2.2 and later if OUTCOME_ENABLE_LEGACY_SUPPORT_FOR is set to less than 220 to enable emulation.

You will note that the naming is simply one of hook_* => on_*, the parameters remain identical. This eases porting code from Outcome v2.1 to v2.2, it’s usually just a case of copy-pasting the ADL hook code into a custom NoValuePolicy.


Policy set event hooks (Outcome v2.2 onwards):


ADL discovered event hooks (before Outcome v2.2):


One criticism often levelled against library-based exception throw alternatives is that they do not provide as rich a set of facilities as C++ exception throws. This section shows you how to configure Outcome, using the event hooks, to take a stack backtrace on construction of an errored result<T, error_code>, and if that result<T, error_code> should ever be converted into an outcome<T, error_code, std::exception_ptr>, a custom std::exception_ptr will be just-in-time synthesised consisting of the std::system_error for the error code, plus an expanded message string containing the stack backtrace of where the error originally occurred.

One can see the use case for such a configuration where low-level, deterministic, fixed latency code is built with result, and it dovetails into higher-level application code built with outcome where execution time guarantees are not important, and thus where a malloc is okay. One effectively has constructed a “lazy indeterminism”, or “just-in-time indeterminism” mechanism for handling failure, but with all the rich information of throwing C++ exceptions.