In use

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

namespace app
  // A markup function to indicate when we are ValueOrError converting
  template <class T> inline outcome<typename T::value_type> ext(T &&v)
  {  //
    return outcome<typename T::value_type>(std::move(v));

  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, ext(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, ext(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, ext(filelib::write_file(data_view)));
    return success();
}  // namespace app
View this code on Github

The curiosity will be surely the ext() markup function, which needs explaining. It was felt important during Outcome’s design that ValueOrError conversions never be implicit, as they almost always represent a transition across an ABI or semantic boundary. They are also usually non-trivial to implement and compile, and it was felt important that the programmer ought to always mark the semantic boundary transition at the point of every use, as considerable amounts of code may execute.

How the end user chooses to mark up their code is up to them, however above we use a simple ext() function to mark up that the function being called is external to the application. This ticks our box of requiring the documentation, at the point of use, of every transition in failure handling boundaries.

Note that we are able to use TRY as normal throughout this function. Everything “just works”.

And most especially note that we never, at any stage, needed to modify the source code of httplib, tidylib nor filelib, nor inject custom things into their namespaces. This entire worked example was achieved solely by app based customisation points, and via convert.