# Boost.System: Extensible Error Reporting

Beman Dawes, Christopher Kohlhoff, Peter Dimov

## Introduction

Errors originating from the operating system or other low-level application program interfaces (APIs) are typically reported via an integer representing an error code, either by returning the code directly from the function (e.g. `pthread_mutex_init`) or by using a side channel such as the `errno` pseudo-variable under POSIX or `GetLastError()` under Windows.

However, these integer error values can only be interpreted when their source is known. The value 5 under Windows means `ERROR_ACCESS_DENIED` when returned by `GetLastError()`, but `EIO` when retrieved from `errno`. And conversely, the same error condition "access denied" is represented by the value 5 when returned by `GetLastError()` and 13 (`EACCES`) when retrieved from `errno`.

This means that in order for code to be able to handle errors from both sources (to retrieve a text message describing the error, or to check whether the error means "access denied"), it needs to know where the integer error value originated. For this to be possible, the integer error value needs to be accompanied by a piece of information identifying the source.

Boost.System provides a framework in which this is possible. Errors are represented by a class `error_code` which contains both the error value and a pointer to their source (called "category"), represented as a class derived from `error_category`.

The category provides member functions such as `message`, which returns a text message for a specific error value, and `equivalent`, which can be used to test whether a specific error value correspond to an error condition such as "access denied". `error_code` uses these category-provided functions in the implementation of its `message` and `operator==` member functions.

Boost.System contains two predefined category classes, the generic category (a reference to which is returned by `generic_category()`) and the system category (`system_category()`). The generic category represents the error values of the portable subset of `errno` values defined by the POSIX standard, whereas the system category is OS dependent. Under POSIX, the system category represents the `errno` values returned by the OS APIs (a superset of those in the generic category), whereas under Windows, the system category represents the error values returned by `GetLastError()`.

The framework is extensible. Users can define their own categories by deriving a class from `error_category` and implementing a function that returns a reference to an instance of it. This capability is useful both for describing library-defined error values, and for adapting existing C API libraries that return integer error values.

For those who prefer error reporting via exceptions, Boost.System provides a standard exception class `system_error` that stores an `error_code`.

Boost.System was standardized in C++11 as `<system_error>`. For a while, the two were equivalent, but Boost.System has evolved since then and now contains a number of extensions over its standard sibling:

- A non-allocating overload of `message`;

- Support for nonzero error codes meaning success, via the `failed` member functions;

- Support for 64 bit category identifiers, as a solution to the problem that sometimes it’s not possible to ensure that only one instance of a category exists in the program;

- Support for attaching source locations (file/line/function) to error codes;

- A class `result<T>` that can be used to return either a value or an error code from a function;

- Various other minor improvements.

`boost::system::error_code` can be converted to, and constructed from, `std::error_code`.

## Usage

All of the following code snippets assume that these lines

    #include <boost/system.hpp>
    namespace sys = boost::system;

are in effect.

### Returning Errors from OS APIs under POSIX

Let’s suppose that we’re implementing a portable `file` wrapper over the OS file APIs. Its general outline is shown below:

    class file
    {
    private:

        int fd_;

    public:

        // ...

        std::size_t read( void * buffer, std::size_t size, sys::error_code& ec );
        std::size_t write( void const * buffer, std::size_t size, sys::error_code& ec );
    };

Since we’re implementing the POSIX version of `file`, its data member is a POSIX file descriptor `int fd_;`, although other implementations will differ.

Our `read` and `write` functions return the number of bytes transferred, and signal errors via the output parameter `ec`, of type `boost::system::error_code`.

An implementation of `file::read` might look like this:

    std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
    {
        ssize_t r = ::read( fd_, buffer, size );

        if( r < 0 )
        {
            ec.assign( errno, sys::system_category() );
            return 0;
        }

        ec = {}; // ec.clear(); under C++03
        return r;
    }

We first call the POSIX API `read`; if it returns an error, we store the `errno` value in `ec`, using the system category, and return 0 as bytes transferred. Otherwise, we clear `ec` to signal success, and return the result of `::read`.

Note | Clearing `ec` on successful returns is an important step; do not omit it.

Under POSIX, the system category corresponds to POSIX `errno` values, which is why we use it.

In principle, since the generic category also corresponds to `errno` values under all platforms, we could have used it here; however, by convention under POSIX, if the `errno` value comes from the OS (the "system"), we use the system category for it. That’s because the system category values may be a platform-specific superset of the generic (platform-independent) values.

The implementation of `file::write` is basically the same. We show it here for completeness:

    std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
    {
        ssize_t r = ::write( fd_, buffer, size );

        if( r < 0 )
        {
            ec.assign( errno, sys::system_category() );
            return 0;
        }

        ec = {}; // ec.clear(); under C++03
        return r;
    }

### Returning Errors from OS APIs under Windows

Under Windows, our `file` object will store a `HANDLE` instead of an `int`:

    class file
    {
    private:

        HANDLE fh_;

    public:

        // as before
    };

and the implementation of `file::read` will look like this:

    std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
    {
        DWORD r = 0;

        if( ::ReadFile( fh_, buffer, size, &r, 0 ) )
        {
            // success
            ec = {}; // ec.clear(); under C++03
        }
        else
        {
            // failure
            ec.assign( ::GetLastError(), sys::system_category() );
        }

        // In both cases, r is bytes transferred
        return r;
    }

Here, the system category corresponds to the values defined in the system header `<winerror.h>` and returned by `GetLastError()`. Since we use the Win32 API `ReadFile` to implement `file::read`, and it returns the error code via `GetLastError()`, we again store that value in `ec` as belonging to the system category.

The implementation of `file::write` is, again, the same.

    std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
    {
        DWORD r = 0;

        if( ::WriteFile( fh_, buffer, size, &r, 0 ) )
        {
            ec = {}; // ec.clear(); under C++03
        }
        else
        {
            ec.assign( ::GetLastError(), sys::system_category() );
        }

        return r;
    }

### Returning Specific Errors under POSIX

Our implementation of `file::read` has a problem; it accepts `std::size_t` values for `size`, but the behavior of `::read` is unspecified when the requested value does not fit in `ssize_t`. To avoid reliance on unspecified behavior, let’s add a check for this condition and return an error:

    std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
    {
        if( size > SSIZE_MAX )
        {
            ec.assign( EINVAL, sys::generic_category() );
            return 0;
        }

        ssize_t r = ::read( fd_, buffer, size );

        if( r < 0 )
        {
            ec.assign( errno, sys::system_category() );
            return 0;
        }

        ec = {}; // ec.clear(); under C++03
        return r;
    }

In this case, since we’re returning the fixed `errno` value `EINVAL`, which is part of the portable subset defined by the generic category, we mark the error value in `ec` as belonging to the generic category.

It’s possible to use system as well, as `EINVAL` is also a system category value under POSIX; however, using the generic category for values belonging to the portable `errno` subset is slightly preferrable.

Our implementation of `file::write` needs to undergo a similar treatment. There, however, we’ll apply another change. When there’s no space left on the disk, `::write` returns a number of bytes written that is lower than what we requested with `size`, but our function signals no error. We’ll make it return `ENOSPC` in this case.

    std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
    {
        if( size > SSIZE_MAX )
        {
            ec.assign( EINVAL, sys::generic_category() );
            return 0;
        }

        ssize_t r = ::write( fd_, buffer, size );

        if( r < 0 )
        {
            ec.assign( errno, sys::system_category() );
            return 0;
        }

        if( r < size )
        {
            ec.assign( ENOSPC, sys::system_category() );
        }
        else
        {
            ec = {}; // ec.clear(); under C++03
        }

        return r;
    }

We’ve used the system category to make it appear that the `ENOSPC` value has come from the `::write` API, mostly to illustrate that this is also a possible approach. Using a generic value would have worked just as well.

### Returning Specific Errors under Windows

Not much to say; the situation under Windows is exactly the same. The only difference is that we must use the generic category for returning `errno` values. The system category does not work; the integer values in the system category are entirely different from those in the generic category.

    std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
    {
        DWORD r = 0;

        if( size > MAXDWORD )
        {
            ec.assign( EINVAL, sys::generic_category() );
        }
        else if( ::ReadFile( fh_, buffer, size, &r, 0 ) )
        {
            ec = {}; // ec.clear(); under C++03
        }
        else
        {
            ec.assign( ::GetLastError(), sys::system_category() );
        }

        return r;
    }

    std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
    {
        DWORD r = 0;

        if( size > MAXDWORD )
        {
            ec.assign( EINVAL, sys::generic_category() );
        }
        else if( ::WriteFile( fh_, buffer, size, &r, 0 ) )
        {
            if( r < size )
            {
                ec.assign( ENOSPC, sys::generic_category() );
            }
            else
            {
                ec = {}; // ec.clear(); under C++03
            }
        }
        else
        {
            ec.assign( ::GetLastError(), sys::system_category() );
        }

        return r;
    }

### Attaching a Source Location to Error Codes

Unlike the standard `<system_error>`, Boost.System allows source locations (file/line/function) to be stored in `error_code`, so that functions handling the error can display or log the source code location where the error occurred. To take advantage of this functionality, our POSIX `file::read` function needs to be augmented as follows:

    std::size_t file::read( void * buffer, std::size_t size, sys::error_code& ec )
    {
        if( size > SSIZE_MAX )
        {
            static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION;
            ec.assign( EINVAL, sys::generic_category(), &loc );
            return 0;
        }

        ssize_t r = ::read( fd_, buffer, size );

        if( r < 0 )
        {
            static constexpr boost::source_location loc = BOOST_CURRENT_LOCATION;
            ec.assign( errno, sys::system_category(), &loc );
            return 0;
        }

        ec = {}; // ec.clear(); under C++03
        return r;
    }

That is, before every `ec.assign` statement, we need to declare a `static constexpr` variable holding the current source location, then pass a pointer to it to `assign`. Since `error_code` is small and there’s no space in it for more than a pointer, we can’t just store the `source_location` in it by value.

`BOOST_CURRENT_LOCATION` is a macro expanding to the current source location (a combination of `__FILE__`, `__LINE__`, and `BOOST_CURRENT_FUNCTION`.) It’s defined and documented in Boost.Assert.

Under C++03, instead of `static constexpr`, one needs to use `static const`. Another option is `BOOST_STATIC_CONSTEXPR`, a Boost.Config macro that expands to either `static constexpr` or `static const`, as appropriate.

To avoid repeating this boilerplate each time we do `ec.assign`, we can define a macro:

    #define ASSIGN(ec, ...) { \
        BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; \
        (ec).assign(__VA_ARGS__, &loc); }

which we can now use to augment, for example, the POSIX implementation of `file::write`:

    std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
    {
        if( size > SSIZE_MAX )
        {
            ASSIGN( ec, EINVAL, sys::generic_category() );
            return 0;
        }

        ssize_t r = ::write( fd_, buffer, size );

        if( r < 0 )
        {
            ASSIGN( ec, errno, sys::system_category() );
            return 0;
        }

        if( r < size )
        {
            ASSIGN( ec, ENOSPC, sys::generic_category() );
        }
        else
        {
            ec = {}; // ec.clear(); under C++03
        }

        return r;
    }

### Obtaining Textual Representations of Error Codes for Logging and Display

Assuming that we have an `error_code` instance `ec`, returned to us by some function, we have a variety of means to obtain textual representations of the error code represented therein.

`ec.to_string()` gives us the result of streaming `ec` into a `std::ostream`, e.g. if `std::cout << ec << std::endl;` outputs `system:6`, this is what `ec.to_string()` will return. (`system:6` under Windows is `ERROR_INVALID_HANDLE` from `<winerror.h>`.)

To obtain a human-readable error message corresponding to this code, we can use `ec.message()`. For `ERROR_INVALID_HANDLE`, it would give us "The handle is invalid" - possibly localized.

If `ec` contains a source location, we can obtain its textual representation via `ec.location().to_string()`. This will give us something like

    C:\Projects\testbed2019\testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)'

if there is a location in `ec`, and

    (unknown source location)

if there isn’t. (`ec.has_location()` is `true` when `ec` contains a location.)

Finally, `ec.what()` will give us a string that contains all of the above, something like

    The handle is invalid [system:6 at C:\Projects\testbed2019\testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)']

Most logging and diagnostic output that is not intended for the end user would probably end up using `what()`. (`ec.what()`, augmented with the prefix supplied at construction, is also what `boost::system::system_error::what()` would return.)

### Composing Functions Returning Error Codes

Let’s suppose that we need to implement a file copy function, with the following interface:

    std::size_t file_copy( file& src, file& dest, sys::error_code& ec );

`file_copy` uses `src.read` to read bytes from `src`, then writes these bytes to `dest` using `dest.write`. This continues until one of these operations signals an error, or until end of file is reached. It returns the number of bytes written, and uses `ec` to signal an error.

Here is one possible implementation:

    std::size_t file_copy( file& src, file& dest, sys::error_code& ec )
    {
        std::size_t r = 0;

        for( ;; )
        {
            unsigned char buffer[ 1024 ];

            std::size_t n = src.read( buffer, sizeof( buffer ), ec );

            // read failed, leave the error in ec and return
            if( ec.failed() ) return r;

            // end of file has been reached, exit loop
            if( n == 0 ) return r;

            r += dest.write( buffer, n, ec );

            // write failed, leave the error in ec and return
            if( ec.failed() ) return r;
        }
    }

Note that there is no longer any difference between POSIX and Windows implementations; their differences are contained in `file::read` and `file::write`. `file_copy` is portable and works under any platform.

The general pattern in writing such higher-level functions is that they pass the output `error_code` parameter `ec` they received from the caller directly as the output parameter to the lower-level functions they are built upon. This way, when they detect a failure in an intermediate operation (by testing `ec.failed()`), they can immediately return to the caller, because the error code is already in its proper place.

Note that `file_copy` doesn’t even need to clear `ec` on success, by using `ec = {};`. Since we’ve already tested `ec.failed()`, we know that `ec` contains a value that means success.

### Providing Dual (Throwing and Nonthrowing) Overloads

Functions that signal errors via an output `error_code& ec` parameter require that the caller check `ec` after calling them, and take appropriate action (such as return immediately, as above.) Forgetting to check `ec` results in logic errors.

While this is a preferred coding style for some, others prefer exceptions, which one cannot forget to check.

An approach that has been introduced by Boost.Filesystem (which later turned into `std::filesystem`) is to provide both alternatives: a nonthrowing function taking `error_code& ec`, as `file_copy` above, and a throwing function that does not take an `error_code` output parameter, and throws exceptions on failure.

This is how this second throwing function is typically implemented:

    std::size_t file_copy( file& src, file& dest )
    {
        sys::error_code ec;
        std::size_t r = file_copy( src, dest, ec );

        if( ec.failed() ) throw sys::system_error( ec, __func__ );

        return r;
    }

That is, we simply call the nonthrowing overload of `file_copy`, and if it signals failure in `ec`, throw a `system_error` exception.

We use our function name `__func__` (`"file_copy"`) as the prefix, although that’s a matter of taste.

Note that typically under this style the overloads taking `error_code& ec` are decorated with `noexcept`, so that it’s clear that they don’t throw exceptions (although we haven’t done so in the preceding examples in order to keep the code C++03-friendly.)

### result<T> as an Alternative to Dual APIs

Instead of providing two functions for every operation, an alternative approach is to make the function return `sys::result<T>` instead of `T`. `result<T>` is a class holding either `T` or `error_code`, similar to `variant<T, error_code>`.

Clients that prefer to check for errors and not rely on exceptions can test whether a `result<T> r` contains a value via `if( r )` or its more verbose equivalent `if( r.has_value() )`, then obtain the value via `*r` or `r.value()`. If `r` doesn’t contain a value, the `error_code` it holds can be obtained with `r.error()`.

Those who prefer exceptions just call `r.value()` directly, without checking. In the no-value case, this will automatically throw a `system_error` corresponding to the `error_code` in `r`.

Assuming our base `file` API is unchanged, this variation of `file_copy` would look like this:

    sys::result<std::size_t> file_copy( file& src, file& dest )
    {
        std::size_t r = 0;
        sys::error_code ec;

        for( ;; )
        {
            unsigned char buffer[ 1024 ];

            std::size_t n = src.read( buffer, sizeof( buffer ), ec );

            if( ec.failed() ) return ec;
            if( n == 0 ) return r;

            r += dest.write( buffer, n, ec );

            if( ec.failed() ) return ec;
        }
    }

The only difference here is that we return `ec` on error, instead of `r`.

Note, however, that we can no longer return both an error code and a number of transferred bytes; that is, we can no longer signal partial success. This is often not an issue at higher levels, but lower-level primitives such as `file::read` and `file::write` might be better off written using the old style.

Nevertheless, to demonstrate how `result` returning APIs are composed, we’ll show how `file_copy` would look if `file::read` and `file::write` returned `result<size_t>`:

    class file
    {
    public:

        // ...

        sys::result<std::size_t> read( void * buffer, std::size_t size );
        sys::result<std::size_t> write( void const * buffer, std::size_t size );
    };

    sys::result<std::size_t> file_copy( file& src, file& dest )
    {
        std::size_t m = 0;

        for( ;; )
        {
            unsigned char buffer[ 1024 ];

            auto r = src.read( buffer, sizeof( buffer ) );
            if( !r ) return r;

            std::size_t n = *r;
            if( n == 0 ) return m;

            auto r2 = dest.write( buffer, n );
            if( !r2 ) return r2;

            std::size_t n2 = *r2;
            m += n2;
        }
    }

### Testing for Specific Error Conditions

Let’s suppose that we have called a function that signals failure using `error_code`, we have passed it an `error_code` variable `ec`, and now for some reason want to check whether the function has failed with an error code of `EINVAL`, "invalid argument".

Since `error_code` can be compared for equality, our first instict might be `if( ec == error_code( EINVAL, generic_category() )`.

This is wrong, and we should never do it.

First, under POSIX, the function might have returned `EINVAL` from the system category (because the error might have been returned by an OS API, and not by the function itself, as was the case in our `read` and `write` implementations.)

Since `error_code` comparisons are exact, `EINVAL` from the generic category does not compare equal to `EINVAL` from the system category.

(And before you start thinking about just comparing `ec.value()` to `EINVAL`, read on.)

Second, under Windows, the function might have returned `error_code( ERROR_INVALID_PARAMETER, system_category() )`. As we have already mentioned, the integer error values in the system category under Windows are completely unrelated to the integer `errno` values.

The correct approach is to compare `ec` not to specific error codes, but to `error_condition( EINVAL, generic_category() )`. Error conditions are a platform-independent way to represent the meaning of the concrete error codes. In our case, all error codes, under both POSIX and Windows, that represent `EINVAL` will compare equal to `error_condition( EINVAL, generic_category() )`.

In short, you should never compare error codes to error codes, and should compare them to error conditions instead. This is the purpose of the `error_condition` class, which is very frequently misunderstood.

Since

    if( ec == sys::error_condition( EINVAL, sys::generic_category() ) )
    {
        // handle EINVAL
    }

is a bit verbose, Boost.System provides enumerator values for the `errno` values against which an error code can be compared directly.

These enumerators are defined in `<boost/system/errc.hpp>`, and enable the above test to be written

    if( ec == sys::errc::invalid_argument )
    {
        // handle EINVAL
    }

which is what one should generally use for testing for a specific error condition, as a best practice.

### Adapting Existing Integer Error Values

Libraries with C (or `extern "C"`) APIs often signal failure by returning a library-specific integer error code (with zero typically being reserved for "no error".) When writing portable C++ wrappers, we need to decide how to expose these error codes, and using `error_code` is a good way to do it.

Because the integer error codes are library specific, and in general match neither `errno` values or system category values, we need to define a library-specific error category.

#### Adapting SQLite Errors

We’ll take SQLite as an example. The general outline of a custom error category is as follows:

    class sqlite3_category_impl: public sys::error_category
    {
        // TODO add whatever's needed here
    };

    sys::error_category const& sqlite3_category()
    {
        static const sqlite3_category_impl instance;
        return instance;
    }

which can then be used similarly to the predefined generic and system categories:

    int r = some_sqlite3_function( ... );
    ec.assign( r, sqlite3_category() );

If we try to compile the above category definition as-is, it will complain about our not implementing two pure virtual member functions, `name` and `message`, so at minimum, we’ll need to add these. In addition, we’ll also implement the non-allocating overload of `message`. It’s not pure virtual, but its default implementation calls the `std::string`-returning overload, and that’s almost never what one wants. (This default implementation is only provided for backward compatibility, in order to not break existing user-defined categories that were written before this overload was added.)

So, the minimum we need to implement is this:

    class sqlite3_category_impl: public sys::error_category
    {
    public:

        const char * name() const noexcept;
        std::string message( int ev ) const;
        char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
    };

`name` is easy, it just returns the category name:

    const char * sqlite3_category_impl::name() const noexcept
    {
        return "sqlite3";
    }

`message` is used to obtain an error message given an integer error code. SQLite provides the function `sqlite3_errstr` for this, so we don’t need to do any work:

    std::string sqlite3_category_impl::message( int ev ) const
    {
        return sqlite3_errstr( ev );
    }

    char const * sqlite3_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
    {
        std::snprintf( buffer, len, "%s", sqlite3_errstr( ev ) );
        return buffer;
    }

and we’re done. `sqlite3_category()` can now be used like the predefined categories, and we can put an SQLite error code `int r` into a Boost.System `error_code ec` by means of `ec.assign( r, sqlite3_category() )`.

#### Adapting ZLib Errors

Another widely used C library is ZLib, and the portion of `zlib.h` that defines its error codes is shown below:

    #define Z_OK            0
    #define Z_STREAM_END    1
    #define Z_NEED_DICT     2
    #define Z_ERRNO        (-1)
    #define Z_STREAM_ERROR (-2)
    #define Z_DATA_ERROR   (-3)
    #define Z_MEM_ERROR    (-4)
    #define Z_BUF_ERROR    (-5)
    #define Z_VERSION_ERROR (-6)
    /* Return codes for the compression/decompression functions. Negative values
     * are errors, positive values are used for special but normal events.
     */

There are three relevant differences with the previous case of SQLite:

- While for SQLite all non-zero values were errors, as is the typical case, here negative values are errors, but positive values are "special but normal", that is, they represent success, not failure;

- ZLib does not provide a function that returns the error message corresponding to a specific error code;

- When `Z_ERRNO` is returned, the error code should be retrieved from `errno`.

Our category implementation will look like this:

    class zlib_category_impl: public sys::error_category
    {
    public:

        const char * name() const noexcept;

        std::string message( int ev ) const;
        char const * message( int ev, char * buffer, std::size_t len ) const noexcept;

        bool failed( int ev ) const noexcept;
    };

    sys::error_category const& zlib_category()
    {
        static const zlib_category_impl instance;
        return instance;
    }

As usual, the implementation of `name` is trivial:

    const char * zlib_category_impl::name() const noexcept
    {
        return "zlib";
    }

We’ll need to work a bit harder to implement `message` this time, as there’s no preexisting function to lean on:

    char const * zlib_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
    {
        switch( ev )
        {
        case Z_OK:            return "No error";
        case Z_STREAM_END:    return "End of stream";
        case Z_NEED_DICT:     return "A dictionary is needed";
        case Z_ERRNO:         return "OS API error";
        case Z_STREAM_ERROR:  return "Inconsistent stream state or invalid argument";
        case Z_DATA_ERROR:    return "Data error";
        case Z_MEM_ERROR:     return "Out of memory";
        case Z_BUF_ERROR:     return "Insufficient buffer space";
        case Z_VERSION_ERROR: return "Library version mismatch";
        }

        std::snprintf( buffer, len, "Unknown zlib error %d", ev );
        return buffer;
    }

This is a typical implementation of the non-throwing `message` overload. Note that `message` is allowed to return something different from `buffer`, which means that we can return character literals directly, without copying them into the supplied buffer first. This allows our function to return the correct message text even when the buffer is too small.

The `std::string` overload of `message` is now trivial:

    std::string zlib_category_impl::message( int ev ) const
    {
        char buffer[ 64 ];
        return this->message( ev, buffer, sizeof( buffer ) );
    }

Finally, we need to implement `failed`, in order to override its default behavior of returning `true` for all nonzero values:

    bool zlib_category_impl::failed( int ev ) const noexcept
    {
        return ev < 0;
    }

This completes the implementation of `zlib_category()` and takes care of the first two bullets above, but we still haven’t addressed the third one; namely, that we need to retrieve the error from `errno` in the `Z_ERRNO` case.

To do that, we’ll define a helper function that would be used to assign a ZLib error code to an `error_code`:

    void assign_zlib_error( sys::error_code & ec, int r )
    {
        if( r != Z_ERRNO )
        {
            ec.assign( r, zlib_category() );
        }
        else
        {
            ec.assign( errno, sys::generic_category() );
        }
    }

so that, instead of using `ec.assign( r, zlib_category() )` directly, code would do

    int r = some_zlib_function( ... );
    assign_zlib_error( ec, r );

We can stop here, as this covers everything we set out to do, but we can take an extra step and enable source locations for our error codes. For that, we’ll need to change `assign_zlib_error` to take a `source_location`:

    void assign_zlib_error( sys::error_code & ec, int r, boost::source_location const* loc )
    {
        if( r != Z_ERRNO )
        {
            ec.assign( r, zlib_category(), loc );
        }
        else
        {
            ec.assign( errno, sys::generic_category(), loc );
        }
    }

Define a helper macro to avoid the boilerplate of defining the `static constexpr` source location object each time:

    #define ASSIGN_ZLIB_ERROR(ec, r) { \
        BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; \
        assign_zlib_error( ec, r, &loc ); }

And then use the macro instead of the function:

    int r = some_zlib_function( ... );
    ASSIGN_ZLIB_ERROR( ec, r );

#### Supporting Comparisons against Conditions

We notice that some of the ZLib error codes correspond to portable `errno` conditions. `Z_STREAM_ERROR`, for instance, is returned in cases where POSIX functions would have returned `EINVAL`; `Z_MEM_ERROR` is `ENOMEM`; and `Z_BUF_ERROR`, insufficient space in the output buffer to store the result, roughly corresponds to `ERANGE`, result out of range.

To encode this relationship, we need to implement either `default_error_condition` or `equivalent` in our category. Since we have a simple one to one mapping, the former will suffice:

    class zlib_category_impl: public sys::error_category
    {
    public:

        const char * name() const noexcept;

        std::string message( int ev ) const;
        char const * message( int ev, char * buffer, std::size_t len ) const noexcept;

        bool failed( int ev ) const noexcept;

        sys::error_condition default_error_condition( int ev ) const noexcept;
    };

The implementation is straightforward:

    sys::error_condition zlib_category_impl::default_error_condition( int ev ) const noexcept
    {
        switch( ev )
        {
        case Z_OK:            return sys::error_condition();
        case Z_STREAM_ERROR:  return sys::errc::invalid_argument;
        case Z_MEM_ERROR:     return sys::errc::not_enough_memory;
        case Z_BUF_ERROR:     return sys::errc::result_out_of_range;
        }

        return sys::error_condition( ev, *this );
    }

Once this is added, we will be able to compare a ZLib `error_code ec` against `errc` enumerators:

    if( ec == sys::errc::not_enough_memory )
    {
        // Z_MEM_ERROR, or ENOMEM
    }

### Defining Library-Specific Error Codes

Let’s suppose that we are writing a library `libmyimg` for reading some hypothetical image format, and that we have defined the following API function for that:

    namespace libmyimg
    {

    struct image;

    void load_image( file& f, image& im, sys::error_code& ec );

    } // namespace libmyimg

(using our portable `file` class from the preceding examples.)

Our hypothetical image format is simple, consisting of a fixed header, followed by the image data, so an implementation of `load_image` might have the following structure:

    namespace libmyimg
    {

    struct image_header
    {
        uint32_t signature;
        uint32_t width;
        uint32_t height;
        uint32_t bits_per_pixel;
        uint32_t channels;
    };

    void load_image_header( file& f, image_header& im, sys::error_code& ec );

    struct image;

    void load_image( file& f, image& im, sys::error_code& ec )
    {
        image_header ih = {};
        load_image_header( f, ih, ec );

        if( ec.failed() ) return;

        if( ih.signature != 0xFF0AD71A )
        {
            // return an "invalid signature" error
        }

        if( ih.width == 0 )
        {
            // return an "invalid width" error
        }

        if( ih.height == 0 )
        {
            // return an "invalid height" error
        }

        if( ih.bits_per_pixel != 8 )
        {
            // return an "unsupported bit depth" error
        }

        if( ih.channels != 1 && ih.channels != 3 && ih.channels != 4 )
        {
            // return an "unsupported channel count" error
        }

        // initialize `im` and read image data

        // ...
    }

    } // namespace libmyimg

We can see that we need to define five error codes of our own. (Our function can also return other kinds of failures in `ec`— those will come from `file::read` which `load_image_header` will use to read the header.)

To define these errors, we’ll use a scoped enumeration type. (This example will take advantage of C++11 features.)

    namespace libmyimg
    {

    enum class error
    {
        success = 0,

        invalid_signature,
        invalid_width,
        invalid_height,
        unsupported_bit_depth,
        unsupported_channel_count
    };

    } // namespace libmyimg

Boost.System supports being told that an enumeration type represents an error code, which enables implicit conversions between the enumeration type and `error_code`. It’s done by specializing the `is_error_code_enum` type trait, which resides in `namespace boost::system` like the rest of the library:

    namespace boost
    {
    namespace system
    {

    template<> struct is_error_code_enum< ::libmyimg::error >: std::true_type
    {
    };

    } // namespace system
    } // namespace boost

Once this is in place, we can now assign values of `libmyimg::error` to `sys::error_code`, which enables the implementation of `load_image` to be written as follows:

    void load_image( file& f, image& im, sys::error_code& ec )
    {
        image_header ih = {};
        load_image_header( f, ih, ec );

        if( ec.failed() ) return;

        if( ih.signature != 0xFF0AD71A )
        {
            ec = error::invalid_signature;
            return;
        }

        if( ih.width == 0 )
        {
            ec = error::invalid_width;
            return;
        }

        if( ih.height == 0 )
        {
            ec = error::invalid_height;
            return;
        }

        if( ih.bits_per_pixel != 8 )
        {
            ec = error::unsupported_bit_depth;
            return;
        }

        if( ih.channels != 1 && ih.channels != 3 && ih.channels != 4 )
        {
            ec = error::unsupported_channel_count;
            return;
        }

        // initialize `image` and read image data

        // ...
    }

This is however not enough; we still need to define the error category for our enumerators, and associate them with it.

The first step follows our previous two examples very closely:

    namespace libmyimg
    {

    class myimg_category_impl: public sys::error_category
    {
    public:

        const char * name() const noexcept;

        std::string message( int ev ) const;
        char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
    };

    const char * myimg_category_impl::name() const noexcept
    {
        return "libmyimg";
    }

    std::string myimg_category_impl::message( int ev ) const
    {
        char buffer[ 64 ];
        return this->message( ev, buffer, sizeof( buffer ) );
    }

    char const * myimg_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
    {
        switch( static_cast<error>( ev ) )
        {
        case error::success:                   return "No error";
        case error::invalid_signature:         return "Invalid image signature";
        case error::invalid_width:             return "Invalid image width";
        case error::invalid_height:            return "Invalid image height";
        case error::unsupported_bit_depth:     return "Unsupported bit depth";
        case error::unsupported_channel_count: return "Unsupported number of channels";
        }

        std::snprintf( buffer, len, "Unknown libmyimg error %d", ev );
        return buffer;
    }

    sys::error_category const& myimg_category()
    {
        static const myimg_category_impl instance;
        return instance;
    }

    } // namespace libmyimg

The second step involves implementing a function `make_error_code` in the namespace of our enumeration type `error` that takes `error` and returns `boost::system::error_code`:

    namespace libmyimg
    {

    sys::error_code make_error_code( error e )
    {
        return sys::error_code( static_cast<int>( e ), myimg_category() );
    }

    } // namespace libmyimg

Now `load_image` will compile, and we just need to fill the rest of its implementation with code that uses `file::read` to read the image data.

There’s one additional embellishment we can make. As we know, Boost.System was proposed for, and accepted into, the C++11 standard, and now there’s a standard implementation of it in `<system_error>`. We can make our error enumeration type compatible with `std::error_code` as well, by specializing the standard type trait `std::is_error_code_enum`:

    namespace std
    {

    template<> struct is_error_code_enum< ::libmyimg::error >: std::true_type
    {
    };

    } // namespace std

This makes our enumerators convertible to `std::error_code`.

(The reason this works is that `boost::system::error_code` is convertible to `std::error_code`, so the return value of our `make_error_code` overload can be used to initialize a `std::error_code`.)

### Defining Library-Specific Error Conditions

All of the `libmyimg::error` error codes we have so far represent the same error condition - invalid or unsupported image format. It might make sense to enable testing for this condition without the need to enumerate all five specific codes. To do this, we can define an error condition enumeration type:

    namespace libmyimg
    {

    enum class condition
    {
        invalid_format = 1
    };

    } // namespace libmyimg

which we can tag as representing an error condition by specializing `is_error_condition_enum`:

    namespace boost
    {
    namespace system
    {

    template<> struct is_error_condition_enum< ::libmyimg::condition >: std::true_type
    {
    };

    } // namespace system
    } // namespace boost

    namespace std
    {

    template<> struct is_error_condition_enum< ::libmyimg::condition >: std::true_type
    {
    };

    } // namespace std

Similarly to the error code enumeration type, which needed a `make_error_code` overload, this one will need to have a `make_error_condition` overload, and a category.

It’s in principle possible to reuse the category we already defined for our error codes, by making the condition values start from, say, 10000 instead of 1. This saves some typing, but a better practice is to use a separate category for the error conditions. So that’s what we’ll do:

    namespace libmyimg
    {

    class myimg_condition_category_impl: public sys::error_category
    {
    public:

        const char * name() const noexcept;

        std::string message( int ev ) const;
        char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
    };

    const char * myimg_condition_category_impl::name() const noexcept
    {
        return "libmyimg_condition";
    }

    std::string myimg_condition_category_impl::message( int ev ) const
    {
        char buffer[ 64 ];
        return this->message( ev, buffer, sizeof( buffer ) );
    }

    char const * myimg_condition_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
    {
        switch( static_cast<condition>( ev ) )
        {
        case condition::invalid_format: return "Invalid or unsupported image format";
        }

        std::snprintf( buffer, len, "Unknown libmyimg condition %d", ev );
        return buffer;
    }

    sys::error_category const& myimg_condition_category()
    {
        static const myimg_condition_category_impl instance;
        return instance;
    }

    sys::error_condition make_error_condition( condition e )
    {
        return sys::error_condition( static_cast<int>( e ), myimg_condition_category() );
    }

    } // namespace libmyimg

We have our condition, but it doesn’t do anything yet. To enable `libmyimg::condition::invalid_format` to compare equal to our error codes, we need to implement `default_error_condition` in the error code category:

    namespace libmyimg
    {

    class myimg_category_impl: public sys::error_category
    {
    public:

        const char * name() const noexcept;

        std::string message( int ev ) const;
        char const * message( int ev, char * buffer, std::size_t len ) const noexcept;

        sys::error_condition default_error_condition( int ev ) const noexcept;
    };

    sys::error_condition myimg_category_impl::default_error_condition( int ev ) const noexcept
    {
        switch( static_cast<error>( ev ) )
        {
        case error::success:

            return {};

        case error::invalid_signature:
        case error::invalid_width:
        case error::invalid_height:
        case error::unsupported_bit_depth:
        case error::unsupported_channel_count:

            return condition::invalid_format;
        }

        return sys::error_condition( ev, *this );
    }

    } // namespace libmyimg

That’s it; now `ec == libmyimg::condition::invalid_format` can be used to test whether `ec` contains one of our error codes corresponding to the "invalid image format" condition.

## Revision History

### Changes in Boost 1.85

- C++03 is no longer supported; a C++11 compiler is required. (This includes GCC 4.8 or later, and MSVC 14.0 (VS 2015) or later.)

- The deprecated header `boost/system/cygwin_error.hpp` has been removed.

- The original and obsolete (32 bit) MinGW is no longer supported. MinGW-w64 (both 64 and 32 bit) is still supported.

- `operator&` now works for `result<void>` (by way of taking a nullary function.)

- Added `operator|=` for `result`.

### Changes in Boost 1.84

- Added support for `result<U&, E>`.

- Added `operator|` for `result`.

- Added `operator&` for `result`.

- Added `operator&=` for `result`.

### Changes in Boost 1.81

- The macro `BOOST_SYSTEM_DISABLE_THREADS` can now be defined to disable the use of `<mutex>` (e.g. on single-threaded libstdc++).

- Added `value_type`, `error_type`, `in_place_value`, `in_place_error` to `result<>`.

- Added `emplace` to `result<>`.

### Changes in Boost 1.80

- When an `error_code` is converted to `std::error_code` and then back to `error_code`, the original is now restored, if possible.

- Reworked the conversion from `error_category` to `std::error_category` to avoid the one-time allocation that shows up on leak checkers.

- Added a constructor that allows replacing the source location of an `error_code`, and a corresponding `assign`.

- Added a converting constructor to `result`.

### Changes in Boost 1.79

- Added a `boost::source_location` parameter to `throw_exception_from_error`.

- Added `throw_exception_from_error` overloads for `errc::errc_t`, `std::error_code`, `std::errc`, `std::exception_ptr`.

- `result<T>::value` now automatically supplies `BOOST_CURRENT_LOCATION` to `throw_exception_from_error` via a default argument.

- Added an `errc::make_error_code` overload taking a source location.

### Changes in Boost 1.78

- Added support for source locations to `error_code`.

- Added `error_code::to_string`, `error_condition::to_string`, `error_code::what`.

- `system_error::what()` now contains the source location, if present.

- Added `result<T, E = error_code>`, a class holding either a value or an error, defined in `<boost/system/result.hpp>`.

### Changes in Boost 1.77

- The conversion operator from `error_category` to `std::error_category` has been improved and no longer requires `<map>` or `<mutex>`.

- The comparison operators of `error_category` are now inline friends instead of member functions (a side effect of the previous change.)

- `error_condition` now defers calling `generic_category()` to avoid instantiating the object until it’s actually needed.

- `error_condition::failed` and `error_condition::message` have been undeprecated, and `operator bool()` now once again returns `failed()`.

- The system category now doesn’t call `generic_category()`, to avoid instantiating the object.

- The return value of `default_error_condition` changes in some cases into an `error_condition` from the generic category, instead of from the system category. This happens on POSIX when the input `error_code` is from the system category and does not correspond to any `errc_t` value.

- The interoperability of `error_code` and `std::error_code` has been improved substantially. It is now possible to construct `boost::system::error_code` from `std::error_code`, and it’s possible to pass `boost::system::error_code` to functions taking `std::error_code&`.

- A stream insertion operator for `error_condition` has been added.

### Changes in Boost 1.76

- `windows_error.hpp` is no longer deprecated.

### Changes in Boost 1.75

- The platform-specific headers `windows_error.hpp`, `linux_error.hpp`, and `cygwin_error.hpp` emit deprecation messages and are slated for removal.

- The old names for `generic_category()` and `system_category()` emit deprecation messages and are slated for removal.

- `error_condition::failed` is deprecated and is slated for removal. `operator bool()` for `error_condition` has been reverted to its old meaning of `value() != 0`. This is done for compatibility with `std::error_condition` as the next release is expected to improve interoperability with `<system_error>` even further. Note that this does not affect `error_code::failed`, which is still alive and well.

- The overload of `error_condition::message` that takes a buffer is deprecated and is slated for removal, for the same reasons. Note that this does not affect `error_code::message`.

### Changes in Boost 1.74

- `operator bool()` now returns `failed()` instead of `value() != 0`.

### Changes in Boost 1.69

- Boost.System is now header-only. A stub library is still built for compatibility, but linking to it is no longer necessary.

- Even more functions have been marked `constexpr`.

- The destructor of `error_category` is now protected and no longer virtual. This is a potentially breaking change but its impact is expected to be limited.

- `error_category` now has a constructor that accepts a 64 bit identifier, enabling distinct category objects to compare equal.

- The constructors of `error_category` are now protected.

- A non-allocating, nonthrowing overload of `message` has been added.

- A virtual function `failed` has been added, allowing categories for which success is not synonymous with 0.

- The deprecated `boost::system::throws` object has been removed.

- `boost::throws()` is now deprecated and its use is discouraged.

- The constructor of `system_error` taking a single `error_code` argument is now explicit.

- `system_error::code()` now returns by value.

### Changes in Boost 1.68

On a C++14 compiler, many Boost.System functions and member functions are now `constexpr`, and `error_code` and `error_condition` are literal classes.

In addition to enabling use in constant expressions (and `constexpr` functions), this significantly improves the quality of the generated code.

As a result of this change, however, now using Boost.System from C++14 or C++17 code requires that the library be also built with C++14 or above. This is the default on GCC 6 and newer, but not on GCC 5 or Clang. One can build Boost for C++14 by passing the `cxxstd=14` option to `b2`.

(Previous versions allowed code built against any C++ standard to link with Boost.System built against any C++ standard. In 1.68, code using any C++ standard can link with Boost.System built with C++14 or above, but if Boost.System is built with C++11 or below, only code also built with C++11 and below can link to it successfully.)

### Changes in Boost 1.65

On a C++11 compiler, Boost.System now provides implicit conversions from `boost::system::error_category`, `error_code`, and `error_condition` to their standard equivalents from `<system_error>`.

This allows libraries to expose a C++11 interface and report errors via `std::error_code` even when using Boost.System, directly or through a dependency such as Boost.ASIO.

## Design Rationale

`error_code` and `error_condition` are designed as value types so they can be copied without slicing and do not require heap allocation, but still have polymorphic behavior based on the error category. This is achieved by abstract base class `error_category` supplying the polymorphic behavior, and `error_code` and `error_condition` containing a pointer to an object of a type derived from `error_category`.

Many of the detailed design decisions were driven by the requirements that users to be able to add additional error categories, and that it be no more difficult to write portable code than system-specific code.

The `operator<<` overload for `error_code` eliminates a misleading conversion to `bool` in code like `cout << ec`, where `ec` is of type `error_code`. It is also useful in its own right.

## Reference

### Macros

When `BOOST_SYSTEM_ENABLE_DEPRECATED` is defined, the library provides deprecated features for compatibility. These features are bound to eventually disappear.

When `BOOST_SYSTEM_USE_UTF8` is defined, on Windows the library returns UTF-8 messages using code page `CP_UTF8` instead of the default `CP_ACP`. This macro has no effect on POSIX.

When `BOOST_SYSTEM_DISABLE_THREADS` is defined, the library assumes that the current platform doesn’t support multiple threads and disables the use of the standard header `<mutex>`, eliminating the mutex locks. The single threaded `libstdc++` is one such platform.

### Deprecated Names

In the process of adding Boost.System to the C++11 standard library, the C++ committee changed some names. To ease transition, Boost.System deprecates the old names, but will provide them when the macro `BOOST_SYSTEM_ENABLE_DEPRECATED` is defined.

Old usage, now deprecated | Replacement
--- | ---
`get_generic_category()` | `generic_category()`
`get_system_category()` | `system_category()`
`namespace posix` | `namespace errc`
`namespace posix_error` | `namespace errc`
`get_posix_category()` | `generic_category()`
`posix_category` | `generic_category()`
`errno_ecat` | `generic_category()`
`native_ecat` | `system_category()`

### <boost/system/​is_error_code_enum.hpp>

#### is_error_code_enum

    namespace boost {
    namespace system {

    template<class T>
      struct is_error_code_enum { static const bool value = false; };

    } // namespace system
    } // namespace boost

Users may specialize `is_error_code_enum` for their error enumeration types to indicate that they should be eligible for automatic conversions to `error_code`. This conversion calls `make_error_code(e)`, which should be provided in the same namespace as the enumeration type.

### <boost/system/​is_error_condition_enum.hpp>

#### is_error_condition_enum

    namespace boost {
    namespace system {

    template<class T>
      struct is_error_condition_enum { static const bool value = false; };

    } // namespace system
    } // namespace boost

Users may specialize `is_error_condition_enum` for their error enumeration types to indicate that they should be eligible for automatic conversions to `error_condition`. This conversion calls `make_error_condition(e)`, which should be provided in the same namespace as the enumeration type.

### <boost/system/​errc.hpp>

#### errc

    namespace boost {
    namespace system {

    namespace errc {
      enum errc_t
      {
        success = 0,
        address_family_not_supported,   //EAFNOSUPPORT
        address_in_use,                 //EADDRINUSE
        address_not_available,          //EADDRNOTAVAIL
        already_connected,              //EISCONN
        argument_list_too_long,         //E2BIG
        argument_out_of_domain,         //EDOM
        bad_address,                    //EFAULT
        bad_file_descriptor,            //EBADF
        bad_message,                    //EBADMSG
        broken_pipe,                    //EPIPE
        connection_aborted,             //ECONNABORTED
        connection_already_in_progress, //EALREADY
        connection_refused,             //ECONNREFUSED
        connection_reset,               //ECONNRESET
        cross_device_link,              //EXDEV
        destination_address_required,   //EDESTADDRREQ
        device_or_resource_busy,        //EBUSY
        directory_not_empty,            //ENOTEMPTY
        executable_format_error,        //ENOEXEC
        file_exists,                    //EEXIST
        file_too_large,                 //EFBIG
        filename_too_long,              //ENAMETOOLONG
        function_not_supported,         //ENOSYS
        host_unreachable,               //EHOSTUNREACH
        identifier_removed,             //EIDRM
        illegal_byte_sequence,          //EILSEQ
        inappropriate_io_control_operation, //ENOTTY
        interrupted,                    //EINTR
        invalid_argument,               //EINVAL
        invalid_seek,                   //ESPIPE
        io_error,                       //EIO
        is_a_directory,                 //EISDIR
        message_size,                   //EMSGSIZE
        network_down,                   //ENETDOWN
        network_reset,                  //ENETRESET
        network_unreachable,            //ENETUNREACH
        no_buffer_space,                //ENOBUFS
        no_child_process,               //ECHILD
        no_link,                        //ENOLINK
        no_lock_available,              //ENOLCK
        no_message_available,           //ENODATA
        no_message,                     //ENOMSG
        no_protocol_option,             //ENOPROTOOPT
        no_space_on_device,             //ENOSPC
        no_stream_resources,            //ENOSR
        no_such_device_or_address,      //ENXIO
        no_such_device,                 //ENODEV
        no_such_file_or_directory,      //ENOENT
        no_such_process,                //ESRCH
        not_a_directory,                //ENOTDIR
        not_a_socket,                   //ENOTSOCK
        not_a_stream,                   //ENOSTR
        not_connected,                  //ENOTCONN
        not_enough_memory,              //ENOMEM
        not_supported,                  //ENOTSUP
        operation_canceled,             //ECANCELED
        operation_in_progress,          //EINPROGRESS
        operation_not_permitted,        //EPERM
        operation_not_supported,        //EOPNOTSUPP
        operation_would_block,          //EWOULDBLOCK
        owner_dead,                     //EOWNERDEAD
        permission_denied,              //EACCES
        protocol_error,                 //EPROTO
        protocol_not_supported,         //EPROTONOSUPPORT
        read_only_file_system,          //EROFS
        resource_deadlock_would_occur,  //EDEADLK
        resource_unavailable_try_again, //EAGAIN
        result_out_of_range,            //ERANGE
        state_not_recoverable,          //ENOTRECOVERABLE
        stream_timeout,                 //ETIME
        text_file_busy,                 //ETXTBSY
        timed_out,                      //ETIMEDOUT
        too_many_files_open_in_system,  //ENFILE
        too_many_files_open,            //EMFILE
        too_many_links,                 //EMLINK
        too_many_symbolic_link_levels,  //ELOOP
        value_too_large,                //EOVERFLOW
        wrong_protocol_type             //EPROTOTYPE
      };

    } // namespace errc

    template<> struct is_error_condition_enum<errc::errc_t>
      { static const bool value = true; };

    constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;

    constexpr error_code make_error_code( errc::errc_t e ) noexcept;

    error_code make_error_code( errc::errc_t e,
      boost::source_location const * loc ) noexcept;

    } // namespace system
    } // namespace boost

The predefined enumeration type `errc::errc_t` provides named constants corresponding to the values of the `<cerrno>` macros.

    constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;

- Returns:

    `error_condition( e, generic_category() )`.

  Since `errc::errc_t` provides a specialization of `is_error_condition_enum` and an overload of `make_error_condition`, it can be converted implicitly to an `error_condition`. This is typically useful when comparing `error_code` values returned from APIs to a portable condition, as in the below example:

-     void api_function( boost::system::error_code& ec );

      void my_function()
      {
          boost::system::error_code ec;
          api_function( ec );

          if( ec == boost::system::errc::no_such_file_or_directory )
          {
              // an entity wasn't found (ENOENT)
              // handle this condition
          }
      }

    constexpr error_code make_error_code( errc::errc_t e ) noexcept;

- Returns:

    `error_code( e, generic_category() )`.

  In addition to `make_error_condition`, `errc::errc_t` provides an overload of `make_error_code`. This allows the creation of generic error codes, an operation typically useful when a function needs to signal a generic failure that does not come from an underlying API, such as for instance an out of memory condition:

-     void my_api_function( boost::system::error_code& ec )
      {
          void* p = std::malloc( 16 );

          if( p == 0 )
          {
              // return ENOMEM
              ec = make_error_code( boost::system::errc::out_of_memory );
              return;
          }

          // use p
      }

    constexpr error_code make_error_code( errc::errc_t e,
      boost::source_location const * loc ) noexcept;

- Returns:

    `error_code( e, generic_category(), loc )`.

  Same as the above overload, but takes a source location.

-     void my_api_function( boost::system::error_code& ec )
      {
          void* p = std::malloc( 16 );

          if( p == 0 )
          {
              // return ENOMEM

              BOOST_STATIC_CONSTEXPR boost::source_location loc =
                BOOST_CURRENT_LOCATION;

              ec = make_error_code( boost::system::errc::out_of_memory, &loc );
              return;
          }

          // use p
      }

### <boost/system/​error_category.hpp>

#### error_category

The class `error_category` defines the base class for types used to identify the source and encoding of a particular category of error code.

Classes may be derived from `error_category` to support categories of errors in addition to those defined in Boost.System.

    namespace boost {
    namespace system {

    class error_category
    {
    public: // noncopyable

        error_category( error_category const & ) = delete;
        error_category& operator=( error_category const & ) = delete;

    protected:

        ~error_category() = default;

        constexpr error_category() noexcept;
        explicit constexpr error_category( unsigned long long id ) noexcept;

    public:

        virtual const char * name() const noexcept = 0;

        virtual error_condition default_error_condition( int ev ) const noexcept;

        virtual bool equivalent( int code, const error_condition & condition )
          const noexcept;
        virtual bool equivalent( const error_code & code, int condition )
          const noexcept;

        virtual std::string message( int ev ) const = 0;
        virtual char const * message( int ev, char * buffer, std::size_t len )
          const noexcept;

        virtual bool failed( int ev ) const noexcept;

        friend constexpr bool operator==( const error_category & lhs,
          const error_category & rhs ) noexcept;
        friend constexpr bool operator!=( const error_category & lhs,
          const error_category & rhs ) noexcept;

        friend constexpr bool operator< ( const error_category & lhs,
          const error_category & rhs ) noexcept;

        operator std::error_category const & () const;

    private:

        unsigned long long id_; // exposition only
    };

    } // namespace system
    } // namespace boost

##### Constructors

    constexpr error_category() noexcept;

- Effects:

    Initializes `id_` to 0.

  Remarks:

    Since equivalence for categories that do not have an identifier is based on comparing object addresses, a user-defined derived category of type `C` that uses this constructor should ensure that only one object of type `C` exists in the program.

    explicit constexpr error_category( unsigned long long id ) noexcept;

- Effects:

    Initializes `id_` to `id`.

  Remarks:

    User-defined derived categories that use this constructor are considered equivalent when their identifiers match. Therefore, those categories may have more than one instance existing in a program, but to minimize the possibility of collision, their identifiers must be randomly chosen (at the time the category is implemented, not at runtime). One way of generating a 64 bit random identifier is https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h.

##### Virtuals

    virtual const char * name() const noexcept = 0;

- Returns:

    In derived classes, a character literal naming the error category.

    virtual error_condition default_error_condition( int ev ) const noexcept;

- Returns:

    - In derived classes, an error condition corresponding to `ev`. The returned error condition will typically come from the generic category.

    - In the default implementation, `error_condition( ev, *this )`.

    virtual bool equivalent( int code, const error_condition & condition )
      const noexcept;

- Returns:

    - In derived classes, `true` when `error_code( code, *this )` is equivalent to `condition`.

    - In the default implementation, `default_error_condition( code ) == condition`.

    virtual bool equivalent( const error_code & code, int condition )
      const noexcept;

- Returns:

    - In derived classes, `true` when `code` is equivalent to `error_condition( condition, *this )`.

    - In the default implementation, `*this == code.category() && code.value() == condition`.

    virtual std::string message( int ev ) const = 0;

- Returns:

    In derived classes, a string that describes the error denoted by `ev`.

    virtual char const * message( int ev, char * buffer, std::size_t len )
      const noexcept;

- Effects:

    - Derived classes should either

      - return a pointer to a character literal describing the error denoted by `ev`, or

      - copy a string describing the error into `buffer`, truncating it to `len-1` characters and storing a null terminator, and return `buffer`. If `len` is 0, nothing is copied, but the function still returns `buffer`. Note that when `len` is 0, `buffer` may be `nullptr`.

    - The default implementation calls `message(ev)` and copies the result into `buffer`, truncating it to `len-1` characters and storing a null terminator. If `len` is 0, copies nothing. Returns `buffer`. If `message(ev)` throws an exception, the string `"Message text unavailable"` is used.

  Example:

        const char* my_category::message(int ev, char* buffer, size_t len) const noexcept
        {
            switch(ev)
            {
            case 0: return "no error";
            case 1: return "voltage out of range";
            case 2: return "impedance mismatch";

            case 31:
            case 32:
            case 33:

                std::snprintf(buffer, len, "component %d failure", ev-30);
                return buffer;

            default:

                std::snprintf(buffer, len, "unknown error %d", ev);
                return buffer;
            }
        }

    virtual bool failed( int ev ) const noexcept;

- Returns:

    - In derived classes, `true` when `ev` represents a failure.

    - In the default implementation, `ev != 0`.

  Remarks:

    All calls to this function with the same `ev` must return the same value.

##### Comparisons

    friend constexpr bool operator==( const error_category & lhs,
      const error_category & rhs ) noexcept;

- Returns:

    `rhs.id_ == 0? &lhs == &rhs: lhs.id_ == rhs.id_`.

  Remarks:

    Two category objects are considered equivalent when they have matching nonzero identifiers, or are the same object.

    friend constexpr bool operator!=( const error_category & lhs,
      const error_category & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

    constexpr bool operator< ( const error_category & lhs,
      const error_category & rhs ) const noexcept;

- Returns:

    - If `lhs.id_ < rhs.id_`, `true`;

    - Otherwise, if `lhs.id_ > rhs.id_`, `false`;

    - Otherwise, if `rhs.id_ != 0`, `false`;

    - Otherwise, `std::less<error_category const *>()( &lhs, &rhs )`.

##### Conversions

    operator std::error_category const & () const;

- Returns:

    A reference to an `std::error_category` object corresponding to `*this`.

### <boost/system/​system_category.hpp>

#### system_category

    namespace boost {
    namespace system {

    constexpr const error_category & system_category() noexcept;

    } // namespace system
    } // namespace boost

    constexpr const error_category & system_category() noexcept;

- Returns:

    A reference to a predefined `error_category` object identifying errors originating from the operating system.

### <boost/system/​generic_category.hpp>

#### generic_category

    namespace boost {
    namespace system {

    constexpr const error_category & generic_category() noexcept;

    } // namespace system
    } // namespace boost

    constexpr const error_category & generic_category() noexcept;

- Returns:

    A reference to a predefined `error_category` object identifying portable error codes and conditions.

### <boost/system/​error_code.hpp>

#### error_code

The class `error_code` describes an object used to hold error code values, such as those originating from the operating system or other low-level application program interfaces. It’s an adjunct to error reporting by exception.

    namespace boost {
    namespace system {

    class error_code {
    public:

        // constructors

        constexpr error_code() noexcept;
        constexpr error_code( int val, const error_category & cat ) noexcept;

        error_code( int val, const error_category & cat,
          boost::source_location const * loc ) noexcept;

        template<class ErrorCodeEnum>
          constexpr error_code( ErrorCodeEnum e ) noexcept;

        error_code( error_code const& ec,
          boost::source_location const * loc ) noexcept;

        error_code( std::error_code const& ec ) noexcept;

        // modifiers

        constexpr void assign( int val, const error_category & cat ) noexcept;

        void assign( int val, const error_category & cat,
          boost::source_location const * loc ) noexcept;

        template<class ErrorCodeEnum>
          constexpr error_code & operator=( ErrorCodeEnum e ) noexcept;

        void assign( error_code const& ec,
          boost::source_location const * loc ) noexcept;

        constexpr void clear() noexcept;

        // observers

        constexpr int value() const noexcept;
        constexpr const error_category & category() const noexcept;

        error_condition default_error_condition() const noexcept;

        std::string message() const;
        char const * message( char * buffer, std::size_t len ) const noexcept;

        constexpr bool failed() const noexcept;
        constexpr explicit operator bool() const noexcept;

        bool has_location() const noexcept;
        boost::source_location const & location() const noexcept;

        // comparisons

        friend constexpr bool operator==( const error_code & lhs,
          const error_code & rhs ) noexcept;

        friend constexpr bool operator!=( const error_code & lhs,
          const error_code & rhs ) noexcept;

        friend constexpr bool operator<( const error_code & lhs,
          const error_code & rhs ) noexcept;

        friend bool operator==( const error_code & code,
          const error_condition & condition ) noexcept;
        friend bool operator==( const error_condition & condition,
          const error_code & code ) noexcept;

        friend bool operator!=( const error_code & code,
          const error_condition & condition ) noexcept;
        friend bool operator!=( const error_condition & condition,
          const error_code & code ) noexcept;

        friend bool operator==( const error_code & lhs,
          const std::error_code & rhs ) noexcept;
        friend bool operator==( const std::error_code & lhs,
          const error_code & rhs ) noexcept;

        friend bool operator!=( const error_code & lhs,
          const std::error_code & rhs ) noexcept;
        friend bool operator!=( const std::error_code & lhs,
          const error_code & rhs ) noexcept;

        template<class E>
          friend constexpr bool operator==( const error_code & lhs, E rhs ) noexcept;
        template<class E>
          friend constexpr bool operator==( E lhs, const error_code & rhs ) noexcept;

        template<class E>
          friend constexpr bool operator!=( const error_code & lhs, E rhs ) noexcept;
        template<class E>
          friend constexpr bool operator!=( E lhs, const error_code & rhs ) noexcept;

        // conversions

        operator std::error_code() const;
        operator std::error_code();
        template<class T> operator T& (); // only when T=std::error_code

        // to_string

        std::string to_string() const;

        // stream insertion

        template<class charT, class traits>
          friend std::basic_ostream<charT, traits>&
            operator<<( basic_ostream<charT, traits>& os, const error_code & ec );

        // what

        std::string what() const;
    };

    // non-member functions

    std::size_t hash_value( const error_code & ec );

    } // namespace system
    } // namespace boost

##### Constructors

    constexpr error_code() noexcept;

- Ensures:

    `value() == 0`; `category() == system_category()`; `!has_location()`.

    constexpr error_code( int val, const error_category & cat ) noexcept;

- Ensures:

    `value() == val`; `category() == cat`; `!has_location()`.

    error_code( int val, const error_category & cat,
      boost::source_location const * loc ) noexcept;

- Requires:

    `loc` points to a valid `boost::source_location` object with static storage duration.

  Ensures:

    `value() == val`; `category() == cat`; `has_location()`; `&location() == loc`.

    template<class ErrorCodeEnum>
      constexpr error_code( ErrorCodeEnum e ) noexcept;

- Ensures:

    `*this == make_error_code( e )`.

  Remarks:

    This constructor is only enabled when `is_error_code_enum<ErrorCodeEnum>::value` is `true`.

    error_code( error_code const& ec,
      boost::source_location const * loc ) noexcept;

- Requires:

    `loc` points to a valid `boost::source_location` object with static storage duration, or is `nullptr`.

  Ensures:

    `*this == ec`.

  Remarks:

    When `ec` is a default-constructed `error_code` or wraps a `std::error_code`, or when `loc` is `nullptr`, `*this` stores no location (`has_location()` is `false`). Otherwise, `*this` stores `loc` (`has_location()` is `true` and `&location()` is `loc`.)

    error_code( std::error_code const & ec ) noexcept;

- Effects:

    Construct an `error_code` that wraps `ec`.

  Remarks:

    `value()` and `category()` are unspecified. `has_location()` is `false`.

##### Modifiers

    constexpr void assign( int val, const error_category & cat ) noexcept;

- Effects:

    `*this = error_code( val, cat )`.

    void assign( int val, const error_category & cat,
      boost::source_location const * loc ) noexcept;

- Effects:

    `*this = error_code( val, cat, loc )`.

    template<class ErrorCodeEnum>
      constexpr error_code & operator=( ErrorCodeEnum e ) noexcept;

- Ensures:

    `*this == make_error_code( e )`.

  Remarks:

    This operator is only enabled when `is_error_code_enum<ErrorCodeEnum>::value` is `true`.

    void assign( error_code const& ec,
      boost::source_location const * loc ) noexcept;

- Effects:

    `*this = error_code( ec, loc )`.

    constexpr void clear() noexcept;

- Effects:

    `*this = error_code()`.

##### Observers

    constexpr int value() const noexcept;

- Returns:

    the error value.

    constexpr const error_category & category() const noexcept;

- Returns:

    the error category.

    error_condition default_error_condition() const noexcept;

- Returns:

    `category().default_error_condition( value() )`.

    std::string message() const;

- Returns:

    If `*this` wraps a `std::error_code` object `ec`, `ec.message()`. Otherwise, `category().message( value() )`.

    char const * message( char * buffer, std::size_t len ) const noexcept;

- Effects:

    If `*this` wraps a `std::error_code` object `ec`, copies the string returned from `ec.message()` into `buffer` and returns `buffer`. Otherwise, returns `category().message( value(), buffer, len )`.

    constexpr bool failed() const noexcept;

- Returns:

    If `*this` wraps a `std::error_code` object `ec`, `ec.value() != 0`. Otherwise, `category().failed( value() )`.

    constexpr explicit operator bool() const noexcept;

- Returns:

    `failed()`.

    bool has_location() const noexcept;

- Returns:

    `true` if `*this` has been constructed with a pointer to a source location, `false` otherwise.

    boost::source_location const & location() const noexcept;

- Returns:

    `*loc` if `*this` has been constructed with a pointer to a source location `loc`, a reference to a default-constructed `boost::source_location` otherwise.

##### Comparisons

    friend constexpr bool operator==( const error_code & lhs,
      const error_code & rhs ) noexcept;

- Returns:

    If both `lhs` and `rhs` wrap `std::error_code` objects `e1` and `e2`, `e1 == e2`. Otherwise, `lhs.value() == rhs.value() && lhs.category() == rhs.category()`.

    friend constexpr bool operator!=( const error_code & lhs,
      const error_code & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

    friend constexpr bool operator<( const error_code & lhs,
      const error_code & rhs ) noexcept;

- Returns:

    If both `lhs` and `rhs` wrap `std::error_code` objects `e1` and `e2`, `e1 < e2`. Otherwise, `lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value())`.

    friend bool operator==( const error_code & code,
      const error_condition & condition ) noexcept;

    friend bool operator==( const error_condition & condition,
      const error_code & code ) noexcept;

- Returns:

    If `code` wraps a `std::error_code` object `ec`, `ec == static_cast<std::error_condition>( condition )`. Otherwise, `code.category().equivalent( code.value(), condition ) || condition.category().equivalent( code, condition.value() )`.

    friend bool operator!=( const error_code & lhs,
      const error_condition & rhs ) noexcept;

    friend bool operator!=( const error_condition & lhs,
      const error_code & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

    friend bool operator==( const error_code & lhs,
      const std::error_code & rhs ) noexcept;

- Returns:

    `static_cast<std::error_code>(lhs) == rhs`.

    friend bool operator==( const std::error_code & lhs,
      const error_code & rhs ) noexcept;

- Returns:

    `lhs == static_cast<std::error_code>(rhs)`.

    friend bool operator!=( const error_code & lhs,
      const std::error_code & rhs ) noexcept;

    friend bool operator!=( const std::error_code & lhs,
      const error_code & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

    template<class E>
      friend constexpr bool operator==( const error_code & lhs, E rhs ) noexcept;

- Effects:

  - When `is_error_code_enum<E>::value` is `true`, returns `lhs == make_error_code(rhs)`;

  - When `is_error_condition_enum<E>::value` is `true`, returns `lhs == make_error_condition(rhs)`;

  - Otherwise, this overload is disabled.

    template<class E>
      friend constexpr bool operator==( E lhs, const error_code & rhs ) noexcept;

- Effects:

  - When `is_error_code_enum<E>::value` is `true`, returns `make_error_code(lhs) == rhs`;

  - When `is_error_condition_enum<E>::value` is `true`, returns `make_error_condition(lhs) == rhs`;

  - Otherwise, this overload is disabled.

    template<class E>
      friend constexpr bool operator!=( const error_code & lhs, E rhs ) noexcept;

    template<class E>
      friend constexpr bool operator!=( E lhs, const error_code & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

  Remarks:

    These overloads are only enabled when `is_error_code_enum<E>::value` is `true` or `is_error_condition_enum<E>::value` is `true`.

##### Conversions

    operator std::error_code() const;

    operator std::error_code();

- Returns:

    If `*this` wraps a `std::error_code` object `ec`, `ec`. Otherwise, `std::error_code( value(), category() )`.

    template<class T> operator T&();

- Effects:

    If `*this` wraps a `std::error_code` object `ec`, returns a reference to `ec`. Otherwise, makes `*this` wrap `std::error_code( *this )`, then returns a reference to it.

  Remarks:

    This operator is only enabled when `T` is `std::error_code`.

##### to_string

    std::string to_string() const;

- Returns:

    If `*this` wraps a `std::error_code` object `e2`, a string that is the concatenation of `"std:"`, `e2.category().name()`, `':'`, and the string representation of `e2.value()`. Otherwise, the concatenation of `category().name()`, `':'`, and the string representation of `value()`.

##### Stream Insertion

    template <class charT, class traits>
      std::basic_ostream<charT, traits>&
        operator<<( basic_ostream<charT, traits>& os, const error_code & ec );

- Effects:

    `os << to_string()`.

  Returns:

    `os`.

##### what

    std::string what() const;

- Returns:

    A string representation of `*this`, suitable for logging and diagnostic output. Typically incorporates `message()`, `to_string()`, and `location().to_string()` (if available.)

##### Nonmembers

    std::size_t hash_value( const error_code & ec );

- Returns:

    If `ec` wraps a `std::error_code` object `e2`, `std::hash<std::error_code>()(e2)`. Otherwise, a hash value representing `ec`.

### <boost/system/​error_condition.hpp>

#### error_condition

    namespace boost {
    namespace system {

    class error_condition {
    public:

        // constructors

        constexpr error_condition() noexcept;
        constexpr error_condition( int val, const error_category & cat ) noexcept;

        template <class ErrorConditionEnum>
          constexpr error_condition( ErrorConditionEnum e ) noexcept;

        // modifiers

        constexpr void assign( int val, const error_category & cat ) noexcept;

        template<typename ErrorConditionEnum>
          constexpr error_condition & operator=( ErrorConditionEnum e ) noexcept;

        constexpr void clear() noexcept;

        // observers

        constexpr int value() const noexcept;
        constexpr const error_category & category() const noexcept;

        std::string message() const;
        char const * message( char * buffer, std::size_t len ) const noexcept;

        constexpr bool failed() const noexcept;
        constexpr explicit operator bool() const noexcept;

        // comparisons

        friend constexpr bool operator==( const error_condition & lhs,
          const error_condition & rhs ) noexcept;

        friend constexpr bool operator!=( const error_condition & lhs,
          const error_condition & rhs ) noexcept;

        friend constexpr bool operator<( const error_condition & lhs,
          const error_condition & rhs ) noexcept;

        friend bool operator==( const std::error_code & code,
          const error_condition & condition ) noexcept;
        friend bool operator==( const error_condition & condition,
          const std::error_code & code ) noexcept;

        friend bool operator!=( const std::error_code & code,
          const error_condition & condition ) noexcept;
        friend bool operator!=( const error_condition & condition,
          const std::error_code & code ) noexcept;

        // conversions

        operator std::error_condition() const;

        // to_string

        std::string to_string() const;

        // stream insertion

        template <class charT, class traits>
          friend std::basic_ostream<charT, traits>&
            operator<<( basic_ostream<charT, traits>& os, const error_condition & en );
    };

    } // namespace system
    } // namespace boost

##### Constructors

    constexpr error_condition() noexcept;

- Ensures:

    `value() == 0`; `category() == generic_category()`.

    constexpr error_condition( int val, const error_category & cat ) noexcept;

- Ensures:

    `value() == val`; `category() == cat`.

    template <class ErrorConditionEnum>
      constexpr error_condition( ErrorConditionEnum e ) noexcept;

- Ensures:

    `*this == make_error_condition( e )`.

  Remarks:

    This constructor is only enabled when `is_error_condition_enum<ErrorConditionEnum>::value` is `true`.

##### Modifiers

    constexpr void assign( int val, const error_category & cat ) noexcept;

- Ensures:

    `value() == val`; `category() == cat`.

    template <class ErrorConditionEnum>
      constexpr error_condition & operator=( ErrorConditionEnum e ) noexcept;

- Ensures:

    `*this == make_error_condition( e )`.

  Remarks:

    This operator is only enabled when `is_error_condition_enum<ErrorConditionEnum>::value` is `true`.

    constexpr void clear() noexcept;

- Ensures:

    `value() == 0`; `category() == generic_category()`.

##### Observers

    constexpr int value() const noexcept;

- Returns:

    the error value.

    constexpr const error_category & category() const noexcept;

- Returns:

    the error category.

    std::string message() const;

- Returns:

    `category().message( value() )`.

    char const * message( char * buffer, std::size_t len ) const noexcept;

- Returns:

    `category().message( value(), buffer, len )`.

    constexpr bool failed() const noexcept;

- Returns:

    `category().failed( value() )`.

    constexpr explicit operator bool() const noexcept;

- Returns:

    `failed()`.

##### Comparisons

    friend constexpr bool operator==( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

- Returns:

    `lhs.value() == rhs.value() && lhs.category() == rhs.category()`.

    friend constexpr bool operator!=( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

    friend constexpr bool operator<( const error_condition & lhs,
      const error_condition & rhs ) noexcept;

- Returns:

    `lhs.category() < rhs.category() || (lhs.category() == rhs.category() && lhs.value() < rhs.value())`.

    friend bool operator==( const std::error_code & code,
      const error_condition & condition ) noexcept;

    friend bool operator==( const error_condition & condition,
      const std::error_code & code ) noexcept;

- Returns:

    `code == static_cast<std::error_condition>( rhs )`.

    friend constexpr bool operator!=( const std::error_code & lhs,
      const error_condition & rhs ) noexcept;

    friend constexpr bool operator!=( const error_condition & lhs,
      const std::error_code & rhs ) noexcept;

- Returns:

    `!( lhs == rhs )`.

##### Conversions

    operator std::error_condition() const;

- Returns:

    `std::error_condition( value(), category() )`.

##### to_string

    std::string to_string() const;

- Returns:

    The concatenation of `"cond:"`, `category().name()`, `':'`, and the string representation of `value()`.

##### Stream Insertion

    template <class charT, class traits>
      std::basic_ostream<charT, traits>&
        operator<<( basic_ostream<charT, traits>& os, const error_condition & en );

- Effects:

    `os << en.to_string()`.

  Returns:

    `os`.

### <boost/system/​system_error.hpp>

#### system_error

The class `system_error` describes an exception object used to report errors that have an associated `error_code`. Such errors typically originate from operating system or other low-level application program interfaces.

    namespace boost {
    namespace system {

    class system_error: public std::runtime_error
    {
    public:

        explicit system_error( error_code ec );
        system_error( error_code ec, const char * what_arg );
        system_error( error_code ec, const std::string & what_arg );

        system_error( int ev, const error_category & ecat );
        system_error( int ev, const error_category & ecat,
          const char * what_arg );
        system_error( int ev, const error_category & ecat,
          const std::string & what_arg );

        error_code code() const noexcept;
        const char * what() const noexcept;
    };

    } // namespace system
    } // namespace boost

##### Constructors

    explicit system_error( error_code ec );
    system_error( error_code ec, const char * what_arg );
    system_error( error_code ec, const std::string & what_arg );

- Ensures:

    `code() == ec`.

    system_error( int ev, const error_category & ecat,
      const char * what_arg );
    system_error( int ev, const error_category & ecat,
      const std::string & what_arg );
    system_error( int ev, const error_category & ecat );

- Ensures:

    `code() == error_code( ev, ecat )`.

##### Observers

    error_code code() const noexcept;

- Returns:

    `ec` or `error_code( ev, ecat )`, from the constructor, as appropriate.

    const char * what() const noexcept;

- Returns:

    A null-terminated character string incorporating the arguments supplied in the constructor, typically of the form `what_arg + ": " + code().message()`.

### <boost/system/result.hpp>

This header defines the class template `result<T, E>`. Unlike the rest of the library, it requires C++11.

#### Synopsis

    namespace boost {
    namespace system {

    // throw_exception_from_error

    BOOST_NORETURN inline void throw_exception_from_error( error_code const & e,
      boost::source_location const & loc );

    BOOST_NORETURN inline void throw_exception_from_error( std::error_code const & e,
      boost::source_location const & loc );

    BOOST_NORETURN inline void throw_exception_from_error( errc::errc_t const & e,
      boost::source_location const & loc );

    BOOST_NORETURN inline void throw_exception_from_error( std::errc const & e,
      boost::source_location const & loc );

    BOOST_NORETURN inline void throw_exception_from_error( std::exception_ptr & e,
      boost::source_location const & loc );

    // in_place_*

    using in_place_value_t = /*unspecified*/;
    constexpr in_place_value_t in_place_value{};

    using in_place_error_t = /*unspecified*/;
    constexpr in_place_error_t in_place_error{};

    // result

    template<class T, class E = error_code> class result;
    template<class E> class result<void, E>;
    template<class U, class E> class result<U&, E>;

    // operator|

    template<class T, class E, class U> T operator|( result<T, E> const& r, U&& u );
    template<class T, class E, class U> T operator|( result<T, E>&& r, U&& u );

    template<class T, class E, class F> T operator|( result<T, E> const& r, F&& f );
    template<class T, class E, class F> T operator|( result<T, E>&& r, F&& f );

    template<class T, class E, class F, class R = ...> R operator|( result<T, E> const& r, F&& f );
    template<class T, class E, class F, class R = ...> R operator|( result<T, E>&& r, F&& f );
    template<class E, class F, class R = ...> R operator|( result<void, E> const& r, F&& f );
    template<class E, class F, class R = ...> R operator|( result<void, E>&& r, F&& f );

    // operator&

    template<class T, class E, class F, class U = ...>
      result<U, E> operator&( result<T, E> const& r, F&& f );
    template<class T, class E, class F, class U = ...>
      result<U, E> operator&( result<T, E>&& r, F&& f );

    template<class T, class E, class F, class R = ...> R operator&( result<T, E> const& r, F&& f );
    template<class T, class E, class F, class R = ...> R operator&( result<T, E>&& r, F&& f );

    // operator&=

    template<class T, class E, class F, class U = ...>
      result<T, E>& operator&=( result<T, E>& r, F&& f );

    template<class T, class E, class F, class R = ...>
      result<T, E>& operator&=( result<T, E>& r, F&& f );

    } // namespace system
    } // namespace boost

#### throw_exception_from_error

The function `throw_exception_from_error` is called by `result<T, E>::value()` when the result holds an error. Its purpose is to throw an exception that represents the error held in the result.

An implementation for the common and default case where `E` is `error_code` is already provided. It throws `system_error(e)`.

If `result<T, E>` is used with other error types, the user is expected to provide an appropriate overload of `throw_exception_from_error` in the namespace of `E`.

    BOOST_NORETURN inline void throw_exception_from_error( error_code const & e,
      boost::source_location const & loc );

- Effects:

    `boost::throw_with_location( system_error( e ), loc )`.

    BOOST_NORETURN inline void throw_exception_from_error( std::error_code const & e,
      boost::source_location const & loc );

- Effects:

    `boost::throw_with_location( std::system_error( e ), loc )`.

    BOOST_NORETURN inline void throw_exception_from_error( errc::errc_t const & e,
      boost::source_location const & loc );

- Effects:

    `boost::throw_with_location( system_error( make_error_code( e ) ), loc )`.

    BOOST_NORETURN inline void throw_exception_from_error( std::errc const & e,
      boost::source_location const & loc );

- Effects:

    `boost::throw_with_location( std::system_error( make_error_code( e ) ), loc )`.

    BOOST_NORETURN inline void throw_exception_from_error( std::exception_ptr & e,
      boost::source_location const & loc );

- Effects:

    - If `e` isn’t null, `std::rethrow_exception( e )`.

    - Otherwise, `boost::throw_with_location( std::bad_exception(), loc )`.

#### result<T, E>

`result<T, E>` stores either a value of type `T`, or an error of type `E`. `E` defaults to `error_code`. In a typical use, functions that can fail return `result<T>`.

    namespace boost {
    namespace system {

    template<class T, class E = error_code> class result
    {
    public:

        using value_type = T;
        using error_type = E;

        static constexpr in_place_value_t in_place_value{};
        static constexpr in_place_error_t in_place_error{};

        // constructors

        constexpr result();

        template<class... A>
          constexpr result( A&&... a );

        template<class... A>
          constexpr result( in_place_value_t, A&&... a );

        template<class... A>
          constexpr result( in_place_error_t, A&&... a );

        template<class T2, class E2>
          constexpr result( result<T2, E2> const& r2 );

        template<class T2, class E2>
          constexpr result( result<T2, E2>&& r2 );

        // queries

        constexpr bool has_value() const noexcept;
        constexpr bool has_error() const noexcept;
        constexpr explicit operator bool() const noexcept;

        // checked value access

        constexpr T& value( boost::source_location const & loc =
          BOOST_CURRENT_LOCATION ) & ;

        constexpr T const& value( boost::source_location const & loc =
          BOOST_CURRENT_LOCATION ) const& ;

        constexpr T&& value( boost::source_location const & loc =
          BOOST_CURRENT_LOCATION ) && ;

        constexpr T const&& value( boost::source_location const & loc =
          BOOST_CURRENT_LOCATION ) const&& ;

        // unchecked value access

        constexpr T* operator->() noexcept;
        constexpr T const* operator->() const noexcept;

        constexpr T& operator*() & noexcept;
        constexpr T const& operator*() const & noexcept;
        constexpr T&& operator*() && noexcept;
        constexpr T const&& operator*() const && noexcept;

        // error access

        constexpr E error() const &;
        constexpr E error() &&;

        // emplace

        template<class... A>
          constexpr T& emplace( A&&... a );

        // swap

        constexpr void swap( result& r );
        friend constexpr void swap( result & r1, result & r2 );

        // equality

        friend constexpr bool operator==( result const & r1, result const & r2 );
        friend constexpr bool operator!=( result const & r1, result const & r2 );
    };

    // stream insertion

    template<class Ch, class Tr, class T, class E>
      std::basic_ostream<Ch, Tr>&
        operator<<( std::basic_ostream<Ch, Tr>& os, result<T, E> const & r );

    } // namespace system
    } // namespace boost

##### Constructors

    constexpr result();

- Ensures:

    `*this` holds the value `T()`.

  Remarks:

    This constructor is only enabled when `std::is_default_constructible<T>::value` is `true`.

    template<class... A>
      constexpr result( A&&... a );

- Effects:

    - If `std::is_constructible<T, A…​>::value && !std::is_constructible<E, A…​>::value`, ensures that `*this` holds the value `T( std::forward<A>(a)…​ )`.

    - If `std::is_constructible<E, A…​>::value && !std::is_constructible<T, A…​>::value`, ensures that `*this` holds the error `E( std::forward<A>(a)…​ )`.

    - Otherwise, this constructor does not participate in overload resolution.

  Remarks:

    This constructor is only enabled when `sizeof…​(A) > 0`.

    template<class... A>
      constexpr result( in_place_value_t, A&&... a );

- Ensures:

    `*this` holds the value `T( std::forward<A>(a)…​ )`.

  Remarks:

    This constructor is only enabled when `std::is_constructible<T, A…​>::value` is `true`.

    template<class... A>
      constexpr result( in_place_error_t, A&&... a );

- Ensures:

    `*this` holds the error `E( std::forward<A>(a)…​ )`.

  Remarks:

    This constructor is only enabled when `std::is_constructible<E, A…​>::value` is `true`.

    template<class T2, class E2>
      constexpr result( result<T2, E2> const& r2 );

- Ensures:

    If `r2.has_value()` is `true`, `*this` holds the value `T( *r2 )`, otherwise `*this` holds the error `E( r2.error() )`.

  Remarks:

    This constructor is only enabled when `std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::value` is `true`.

    template<class T2, class E2>
      constexpr result( result<T2, E2>&& r2 );

- Ensures:

    If `r2.has_value()` is `true`, `*this` holds the value `T( std::move( *r2 ) )`, otherwise `*this` holds the error `E( r2.error() )`.

  Remarks:

    This constructor is only enabled when `std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::value` is `true`.

##### Queries

    constexpr bool has_value() const noexcept;

- Returns:

    `true` when `*this` holds a value, `false` otherwise.

    constexpr bool has_error() const noexcept;

- Returns:

    `!has_value()`.

    constexpr explicit operator bool() const noexcept;

- Returns:

    `has_value()`.

##### Checked Value Access

    constexpr T& value(
      boost::source_location const & loc = BOOST_CURRENT_LOCATION ) & ;

    constexpr T const& value(
      boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const& ;

    constexpr T&& value(
      boost::source_location const & loc = BOOST_CURRENT_LOCATION ) && ;

    constexpr T const&& value(
      boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const&& ;

- Effects:

    If `*this` holds a value, returns a reference to it. Otherwise, calls `throw_exception_from_error`, passing it a reference to the held error, and `loc`.

##### Unchecked Value Access

    constexpr T* operator->() noexcept;
    constexpr T const* operator->() const noexcept;

- Returns:

    If `*this` holds a value, a pointer to it. Otherwise, `nullptr`.

    constexpr T& operator*() & noexcept;
    constexpr T const& operator*() const & noexcept;

- Requires:

    `*this` holds a value.

  Returns:

    `*operator->()`.

    constexpr T&& operator*() && noexcept;
    constexpr T const&& operator*() const && noexcept;

- Requires:

    `*this` holds a value.

  Returns:

    `std::move( *operator->() )`.

##### Error Access

    constexpr E error() const &;
    constexpr E error() &&;

- Effects:

    If `*this` holds an error, returns it. Otherwise, returns `E()`.

##### emplace

    template<class... A>
      constexpr T& emplace( A&&... a );

- Ensures:

    `*this` holds the value `T( std::forward<A>(a)…​ )`.

  Returns:

    A reference to the contained value.

##### swap

    constexpr void swap( result& r );

- Effects:

    Exchanges the contents of `*this` and `r`.

    friend constexpr void swap( result & r1, result & r2 );

- Effects:

    Exchanges the contents of `r1` and `r2`.

##### Equality

    friend constexpr bool operator==( result const & r1, result const & r2 );

- Effects:

    - If `r1` holds a value `t1` and `r2` holds a value `t2`, returns `t1 == t2`.

    - If `r1` holds an error `e1` and `r2` holds an error `e2`, returns `e1 == e2`.

    - Otherwise, returns `false`.

    friend constexpr bool operator!=( result const & r1, result const & r2 );

- Returns:

    `!( r1 == r2 )`.

##### Stream Insertion

    template<class Ch, class Tr, class T, class E>
      std::basic_ostream<Ch, Tr>&
        operator<<( std::basic_ostream<Ch, Tr>& os, result<T, E> const & r );

- Effects:

    - If `*this` holds a value `t`, `os << "value:" << t`.

    - If `*this` holds an error `e`, `os << "error:" << e`.

  Returns:

    `os`.

#### result<void, E>

    namespace boost {
    namespace system {

    template<class E> class result<void, E>
    {
    public:

        using value_type = void;
        using error_type = E;

        static constexpr in_place_value_t in_place_value{};
        static constexpr in_place_error_t in_place_error{};

        // constructors

        constexpr result() noexcept;

        template<class... A>
          constexpr result( A&&... a );

        constexpr result( in_place_value_t ) noexcept;

        template<class... A>
          constexpr result( in_place_error_t, A&&... a );

        template<class E2>
          constexpr result( result<void, E2> const& r2 );

        // queries

        constexpr bool has_value() const noexcept;
        constexpr bool has_error() const noexcept;
        constexpr explicit operator bool() const noexcept;

        // checked value access

        constexpr void value( boost::source_location const & loc =
          BOOST_CURRENT_LOCATION ) const;

        // unchecked value access

        constexpr void* operator->() noexcept;
        constexpr void const* operator->() const noexcept;

        constexpr void operator*() const noexcept;

        // error access

        constexpr E error() const &;
        constexpr E error() &&;

        // emplace

        constexpr void emplace();

        // swap

        constexpr void swap( result& r );
        friend constexpr void swap( result & r1, result & r2 );

        // equality

        friend constexpr bool operator==( result const & r1, result const & r2 );
        friend constexpr bool operator!=( result const & r1, result const & r2 );
    };

    // stream insertion

    template<class Ch, class Tr, class E>
      std::basic_ostream<Ch, Tr>&
        operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r );

    } // namespace system
    } // namespace boost

##### Constructors

    constexpr result() noexcept;

- Ensures:

    `*this` holds an unspecified value.

    template<class... A>
      constexpr result( A&&... a );

- Effects:

    - If `std::is_constructible<E, A…​>::value`, ensures that `*this` holds the error `E( std::forward<A>(a)…​ )`.

    - Otherwise, this constructor does not participate in overload resolution.

  Remarks:

    This constructor is only enabled when `sizeof…​(A) > 0`.

    template<class... A>
      constexpr result( in_place_value_t ) noexcept;

- Ensures:

    `*this` holds an unspecified value.

    template<class... A>
      constexpr result( in_place_error_t, A&&... a );

- Ensures:

    `*this` holds the error `E( std::forward<A>(a)…​ )`.

  Remarks:

    This constructor is only enabled when `std::is_constructible<E, A…​>::value` is `true`.

    template<class E2>
      constexpr result( result<void, E2> const& r2 );

- Ensures:

    If `r2.has_value()` is `true`, `*this` holds an unspecified value, otherwise `*this` holds the error `E( r2.error() )`.

  Remarks:

    This constructor is only enabled when `std::is_convertible<E2, E>::value` is `true`.

##### Queries

    constexpr bool has_value() const noexcept;

- Returns:

    `true` when `*this` holds a value, `false` otherwise.

    constexpr bool has_error() const noexcept;

- Returns:

    `!has_value()`.

    constexpr explicit operator bool() const noexcept;

- Returns:

    `has_value()`.

##### Checked Value Access

    constexpr void value(
      boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;

- Effects:

    If `*this` doesn’t hold a value, calls `throw_exception_from_error`, passing it a reference to the held error, and `loc`.

##### Unchecked Value Access

    constexpr void* operator->() noexcept;
    constexpr void const* operator->() const noexcept;

- Returns:

    If `*this` holds a value, a pointer to it. Otherwise, `nullptr`.

    constexpr void operator*() const noexcept;

- Requires:

    `*this` holds a value.

  Effects:

    none.

##### Error Access

    constexpr E error() const &;
    constexpr E error() &&;

- Effects:

    If `*this` holds an error, returns it. Otherwise, returns `E()`.

##### emplace

    constexpr void emplace();

- Ensures:

    `*this` holds an unspecified value.

##### swap

    constexpr void swap( result& r );

- Effects:

    Exchanges the contents of `*this` and `r`.

    friend constexpr void swap( result & r1, result & r2 );

- Effects:

    Exchanges the contents of `r1` and `r2`.

##### Equality

    friend constexpr bool operator==( result const & r1, result const & r2 );

- Effects:

    - If `r1` and `r2` hold values, returns `true`.

    - If `r1` holds an error `e1` and `r2` holds an error `e2`, returns `e1 == e2`.

    - Otherwise, returns `false`.

    friend constexpr bool operator!=( result const & r1, result const & r2 );

- Returns:

    `!( r1 == r2 )`.

##### Stream Insertion

    template<class Ch, class Tr, class E>
      std::basic_ostream<Ch, Tr>&
        operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r );

- Effects:

    - If `*this` holds a value, `os << "value:void"`.

    - If `*this` holds an error `e`, `os << "error:" << e`.

  Returns:

    `os`.

#### result<U&, E>

    namespace boost {
    namespace system {

    template<class U, class E> class result<U&, E>
    {
    public:

        using value_type = U&;
        using error_type = E;

        static constexpr in_place_value_t in_place_value{};
        static constexpr in_place_error_t in_place_error{};

        // constructors

        template<class A>
          constexpr result( A&& a ) noexcept;

        template<class... A>
          constexpr result( A&&... a );

        template<class A>
          constexpr result( in_place_value_t, A&& a ) noexcept;

        template<class... A>
          constexpr result( in_place_error_t, A&&... a );

        template<class U2, class E2>
          constexpr result( result<U2&, E2> const& r2 );

        // queries

        constexpr bool has_value() const noexcept;
        constexpr bool has_error() const noexcept;
        constexpr explicit operator bool() const noexcept;

        // checked value access

        constexpr U& value( boost::source_location const & loc =
          BOOST_CURRENT_LOCATION ) const;

        // unchecked value access

        constexpr U* operator->() const noexcept;
        constexpr U& operator*() const noexcept;

        // error access

        constexpr E error() const &;
        constexpr E error() &&;

        // emplace

        template<class A>
          constexpr U& emplace( A&& a ) noexcept;

        // swap

        constexpr void swap( result& r );
        friend constexpr void swap( result & r1, result & r2 );

        // equality

        friend constexpr bool operator==( result const & r1, result const & r2 );
        friend constexpr bool operator!=( result const & r1, result const & r2 );
    };

    } // namespace system
    } // namespace boost

##### Constructors

    template<class A>
      constexpr result( A&& a ) noexcept;

- Ensures:

    `*this` holds the reference `static_cast<U&>( std::forward<A>(a) )`.

  Remarks:

    This constructor is only enabled when `A` is `B&` and `std::is_convertible<B*, U*>::value` is `true`.

    template<class... A>
      constexpr result( A&&... a );

- Effects:

    - If `std::is_constructible<E, A…​>::value && !std::is_constructible<U&, A…​>::value`, ensures that `*this` holds the error `E( std::forward<A>(a)…​ )`.

    - Otherwise, this constructor does not participate in overload resolution.

  Remarks:

    This constructor is only enabled when `sizeof…​(A) > 0`.

    template<class A>
      constexpr result( in_place_value_t, A&& a ) noexcept;

- Ensures:

    `*this` holds the reference `static_cast<U&>( std::forward<A>(a) )`.

  Remarks:

    This constructor is only enabled when `A` is `B&` and `std::is_convertible<B*, U*>::value` is `true`.

    template<class... A>
      constexpr result( in_place_error_t, A&&... a );

- Ensures:

    `*this` holds the error `E( std::forward<A>(a)…​ )`.

  Remarks:

    This constructor is only enabled when `std::is_constructible<E, A…​>::value` is `true`.

    template<class U2, class E2>
      constexpr result( result<U2&, E2> const& r2 );

- Ensures:

    If `r2.has_value()` is `true`, `*this` holds the reference `static_cast<U&>( *r2 )`, otherwise `*this` holds the error `E( r2.error() )`.

  Remarks:

    This constructor is only enabled when `std::is_convertible<U2*, U*>::value && std::is_convertible<E2, E>::value` is `true`.

##### Queries

    constexpr bool has_value() const noexcept;

- Returns:

    `true` when `*this` holds a value, `false` otherwise.

    constexpr bool has_error() const noexcept;

- Returns:

    `!has_value()`.

    constexpr explicit operator bool() const noexcept;

- Returns:

    `has_value()`.

##### Checked Value Access

    constexpr U& value(
      boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;

- Effects:

    If `*this` holds a reference, returns it. Otherwise, calls `throw_exception_from_error`, passing it a reference to the held error, and `loc`.

##### Unchecked Value Access

    constexpr U* operator->() const noexcept;

- Returns:

    If `*this` holds a reference, a pointer to its referent. Otherwise, `nullptr`.

    constexpr U& operator*() const noexcept;

- Requires:

    `*this` holds a reference.

  Returns:

    `*operator->()`.

##### Error Access

    constexpr E error() const &;
    constexpr E error() &&;

- Effects:

    If `*this` holds an error, returns it. Otherwise, returns `E()`.

##### emplace

    template<class A>
      constexpr U& emplace( A&& a ) noexcept;

- Ensures:

    `*this` holds the reference `static_cast<U&>( std::forward<A>(a)…​ )`.

  Returns:

    The contained reference.

  Remarks:

    This function is only enabled when `A` is `B&` and `std::is_convertible<B*, U*>::value` is `true`.

##### swap

    constexpr void swap( result& r );

- Effects:

    Exchanges the contents of `*this` and `r`.

    friend constexpr void swap( result & r1, result & r2 );

- Effects:

    Exchanges the contents of `r1` and `r2`.

##### Equality

    friend constexpr bool operator==( result const & r1, result const & r2 );

- Effects:

    - If `r1` holds a reference `t1` and `r2` holds a reference `t2`, returns `t1 == t2`.

    - If `r1` holds an error `e1` and `r2` holds an error `e2`, returns `e1 == e2`.

    - Otherwise, returns `false`.

    friend constexpr bool operator!=( result const & r1, result const & r2 );

- Returns:

    `!( r1 == r2 )`.

#### Chaining

##### operator|

    template<class T, class E, class U> T operator|( result<T, E> const& r, U&& u );
    template<class T, class E, class U> T operator|( result<T, E>&& r, U&& u );

- Returns the value in `r`, or if `r` contains an error, a default value `u`.

  Effects:

    - If `r.has_value()` is `true`, returns `*r`.

    - Otherwise, returns `u`.

  Remarks:

    Only enabled when `U` is convertible to `T`.

  Example:

        result<int> get_server_port(); // can fail

        int get_port()
        {
            return get_server_port() | 443;
        }

    template<class T, class E, class F> T operator|( result<T, E> const& r, F&& f );
    template<class T, class E, class F> T operator|( result<T, E>&& r, F&& f );

- Returns the value in `r`, or if `r` contains an error, a default value obtained by invoking the function `f`.

  Effects:

    - If `r.has_value()` is `true`, returns `*r`.

    - Otherwise, returns `f()`.

  Remarks:

    Only enabled when `f()` is convertible to `T`.

  Example:

        result<int> get_server_port(); // can fail
        int get_default_port();

        int get_port()
        {
            return get_server_port() | get_default_port;
        }

    Note that the right hand side is `get_default_port` and not `get_default_port()`. This is important; spelled this way, the function `get_default_port` is called only when `get_server_port_impl()` fails. If it were

            return get_server_port() | get_default_port();

    the function would have been called unconditionally.

    Another, equivalent, way is to use a lambda

            return get_server_port() | []{ return get_default_port(); };

    which isn’t necessary here, but would be needed for more complex expressions.

    template<class T, class E, class F, class R = ...> R operator|( result<T, E> const& r, F&& f );
    template<class T, class E, class F, class R = ...> R operator|( result<T, E>&& r, F&& f );
    template<class E, class F, class R = ...> R operator|( result<void, E> const& r, F&& f );
    template<class E, class F, class R = ...> R operator|( result<void, E>&& r, F&& f );

- Returns the value in `r`, or if `r` contains an error, another `result` obtained by invoking the function `f`.

  Let `R` be the type of `f()`.

  Effects:

    - If `r.has_value()` is `true`, returns `*r`.

    - Otherwise, returns `f()`.

  Remarks:

    Only enabled when `R` is an instance of `result` and `T` is convertible to `R::value_type`.

  Example:

        result<int> get_server_port(); // can fail
        result<int> get_default_port(); // can fail

        int get_port()
        {
            return get_server_port() | get_default_port | 443;
        }

##### operator|=

    template<class T, class E, class U> result<T, E>& operator|=( result<T, E>& r, U&& u );

- If `r` contains an error, assigns a value to it, constructed from `u`.

  Effects:

    If `r.has_value()` is `false`, assigns `u` to `r`.

  Returns:

    `r`.

  Remarks:

    Only enabled when `U` is convertible to `T`.

    template<class T, class E, class F> result<T, E>& operator|=( result<T, E>& r, F&& f );

- If `r` contains an error, assigns `f()` to it.

  Effects:

    If `r.has_value()` is `false`, assigns `f()` to `r`.

  Returns:

    `r`.

  Remarks:

    Only enabled when the type of `f()` is either

    - convertible to `T` or

    - an instance of `result` convertible to `result<T, E>`.

  Example:

        result<response> query_impl( std::string_view server, request const& req );

        result<response> query( std::vector<std::string_view> const& servers, request const& req )
        {
            result<response> r = make_error_code( errc::invalid_argument );

            for( auto const& server: servers )
            {
                r |= std::bind( query_impl, server, std::ref( req ) );
            }

            return r;
        }

##### operator&

    template<class T, class E, class F, class U = ...>
      result<U, E> operator&( result<T, E> const& r, F&& f );

    template<class T, class E, class F, class U = ...>
      result<U, E> operator&( result<T, E>&& r, F&& f );

- Returns the error in `r`, or if `r` contains a value, transforms the value by calling `f` on it.

  Let `U` be the type of `f(*r)`.

  Effects:

    - If `r.has_value()` is `true`, returns `f(*r)`.

    - Otherwise, returns `r.error()`.

  Remarks:

    Only enabled when `U` is not an instance of `result`.

  Example:

        struct currency_type
        {
            char code_[ 4 ] = {};
        };

        result<double> get_exchange_rate( currency_type from, currency_type to );

        result<double> convert( double amount, currency_type from, currency_type to )
        {
            return get_exchange_rate( from, to ) & [&](double rate){ return rate * amount; };
        }

    template<class E, class F, class U = ...>
      result<U, E> operator&( result<void, E> const& r, F&& f );

- Returns the error in `r`, or if `r` contains a value, replaces it with the result of calling `f`.

  Let `U` be the type of `f()`.

  Effects:

    - If `r.has_value()` is `true`, returns `f()`.

    - Otherwise, returns `r.error()`.

  Remarks:

    Only enabled when `U` is not an instance of `result`.

    template<class T, class E, class F, class R = ...> R operator&( result<T, E> const& r, F&& f );
    template<class T, class E, class F, class R = ...> R operator&( result<T, E>&& r, F&& f );

- Returns the error in `r`, or if `r` contains a value, another `result` obtained by invoking the function `f` on the value in `r`.

  Let `R` be the type of `f(*r)`.

  Effects:

    - If `r.has_value()` is `true`, returns `f(*r)`.

    - Otherwise, returns `r.error()`.

  Remarks:

    Only enabled when `R` is an instance of `result` and `E` is convertible to `R::error_type`.

  Example:

        struct JsonValue
        {
            result<JsonValue const&> at( std::size_t i ) const noexcept;
            result<JsonValue const&> at( std::string_view key ) const noexcept;
            template<class T> result<T> to_number() const noexcept;
        };

        namespace helpers
        {

        inline auto at( std::size_t i ) {
            return [=](JsonValue const& jv){ return jv.at( i ); }; }

        inline auto at( std::string_view key ) {
            return [=](JsonValue const& jv){ return jv.at( key ); }; }

        template<class T> inline auto to_number() {
            return [](JsonValue const& jv){ return jv.to_number<T>(); }; }

        } // namespace helpers

        int get_port( JsonValue const& config, int def )
        {
            using namespace helpers;
            return config.at( "servers" ) & at( 0 ) & at( "port" ) & to_number<int>() | def;
        }

    template<class E, class F, class R = ...> R operator&( result<void, E> const& r, F&& f );

- Returns the error in `r`, or if `r` contains a value, another `result` obtained by invoking the function `f`.

  Let `R` be the type of `f()`.

  Effects:

    - If `r.has_value()` is `true`, returns `f()`.

    - Otherwise, returns `r.error()`.

  Remarks:

    Only enabled when `R` is an instance of `result` and `E` is convertible to `R::error_type`.

##### operator&=

    template<class T, class E, class F, class U = ...>
      result<T, E>& operator&=( result<T, E>& r, F&& f );

- If `r` contains a value, replaces it with the result of invoking the function `f` on the value in `r`.

  Let `U` be the type of `f(*r)`.

  Effects:

    If `r.has_value()` is `true`, assigns `f(*std::move(r))` to `r`.

  Returns:

    `r`.

  Remarks:

    Only enabled when `U` is not an instance of `result` and is convertible to `T`.

    template<class T, class E, class F, class R = ...>
      result<T, E>& operator&=( result<T, E>& r, F&& f );

- If `r` contains a value, replaces `r` with the result of invoking the function `f` on the value in `r`.

  Let `R` be the type of `f(*r)`.

  Effects:

    If `r.has_value()` is `true`, assigns `f(*std::move(r))` to `r`.

  Returns:

    `r`.

  Remarks:

    Only enabled when `R` is an instance of `result` and is convertible to `result<T, E>`.

  Example:

        struct JsonValue
        {
            result<JsonValue const&> at( std::string_view key ) const noexcept;
        };

        namespace helpers
        {

        inline auto at( std::string_view key ) {
            return [=](JsonValue const& jv){ return jv.at( key ); }; }

        } // namespace helpers

        result<JsonValue const&> at_path( JsonValue const& jv,
            std::initializer_list<std::string_view> path )
        {
            result<JsonValue const&> r( jv );

            using namespace helpers;

            for( auto key: path )
            {
                r &= at( key );
            }

            return r;
        }

    template<class E, class F, class R = ...>
      result<void, E>& operator&=( result<void, E>& r, F&& f );

- If `r` contains a value, replaces `r` with the result of invoking the function `f`.

  Let `R` be the type of `f()`.

  Effects:

    If `r.has_value()` is `true`, assigns `f()` to `r`.

  Returns:

    `r`.

  Remarks:

    Only enabled when `R` is an instance of `result<void, E2>` and `E2` is convertible to `E`.

### <boost/system.hpp>

This convenience header includes all the headers previously described.

## History

N1975, Filesystem Library Proposal for TR2, accepted for Library Technical Report 2 (TR2) at the Berlin meeting, included additional components to supplement the Standard Library’s Diagnostics clause. Since then, these error reporting components have received wider public scrutiny and enhancements have been made to the design. The enhanced version has been used by N2054, Networking Library Proposal for TR2, demonstrating that these error reporting components are useful beyond the original Filesystem Library.

The original proposal viewed error categories as a binary choice between `errno` (i.e. POSIX-style) and the native operating system’s error codes. The proposed components now allow as many additional error categories as are needed by either implementations or by users. The need to support additional error categories, for example, occurs in some networking library implementations because they are built on top of the POSIX `getaddrinfo` API that uses error codes not based on `errno`.

## Acknowledgments

Christopher Kohlhoff and Peter Dimov made important contributions to the design. Comments and suggestions were also received from Pavel Vozenilek, Gennaro Prota, Dave Abrahams, Jeff Garland, Iain Hanson, Oliver Kowalke, and Oleg Abrosimov. Christopher Kohlhoff suggested several improvements to the N2066 paper. Johan Nilsson’s comments led to several of the refinements in N2066.

## Copyright and License

This documentation is

- Copyright 2003-2017 Beman Dawes

- Copyright 2018-2022 Peter Dimov

and is distributed under the Boost Software License, Version 1.0.