In use

This is how you might now write application code using these three libraries:

namespace app
  outcome<void> go()  // NOT noexcept, this can throw STL exceptions e.g. bad_alloc
    // Note that explicit construction is required when converting between differing types
    // of outcome and result. This makes it explicit what you intend to do as conversion
    // may be a lot more expensive than moves.

    // Try to GET this URL. If an unsuccessful HTTP status is returned, serialise a string
    // containing a description of the HTTP status code and the URL which failed, storing
    // that into a httplib_error exception type which is stored as an exception ptr. The
    // TRY operation below will return that exception ptr to be rethrown in the caller.
    // Otherwise the fetched data is returned in a std::string data.
    OUTCOME_TRY(data, outcome<std::string>(httplib::get("")));
    string_view data_view(data);

    // HTML tidy the fetched data. If the C library fails due to an error corresponding to
    // a standard library exception type, throw that. Otherwise, synthesise an exception
    // ptr of type tidylib_error which stores the error code returned in an error code with
    // generic category (i.e. errno domain).
    // TRY operation below will return that exception ptr to be rethrown in the caller.
    // Otherwise the tidied data is returned into holdmem, with the string view updated to
    // point at the tidied data.
    OUTCOME_TRY(holdmem, tidy_html(data_view));

    // Write the tidied data to some file. If the write fails, synthesise a filesystem_error
    // exception ptr exactly as if one called filelib::write_file(data_view).value().
    OUTCOME_TRY(written, outcome<size_t>(filelib::write_file(data_view)));
    return success();
View this code on Github

Many will wish that the explicit converting wrappers around third party library APIs were not there. Note that in C++ 17 you should be able to dispense with the angle bracketed type as the compiler can now deduce that. But one must still wrap all third party API invocations with outcome() i.e. explicit construction to namespace-localised outcome. This is a deliberate design decision: in Outcome, all converting construction is always explicit, except when the source is success or failure type sugar. And down the line when others come to maintain this code, we think it will be very useful to be explicit on this because user defined code that we customised earlier is being executed.

Note also that we are able to use TRY throughout this function, and most especially note that we never, at any stage, needed to modify the source code of httplib, tidylib nor filelib, or inject custom things into their namespaces. This entire worked example was achieved solely by app based customisation points and via convert.