引言

源自操作系统或其他低级应用程序接口 (API) 的错误通常通过表示错误代码的整数报告,方法是直接从函数返回代码(例如 `pthread_mutex_init`)或使用诸如 POSIX 下的 `errno` 伪变量或 Windows 下的 `GetLastError()` 之类的旁路通道。

但是,只有在知道其来源时才能解释这些整型错误值。 Windows 下的值 5 表示 `ERROR_ACCESS_DENIED`,当由 `GetLastError()` 返回时,但表示 `EIO`,当从 `errno` 检索时。反之,相同的错误条件“访问被拒绝”由值 5 表示,当由 `GetLastError()` 返回时,由 13 (`EACCES`) 表示,当从 `errno` 检索时。

这意味着为了使代码能够处理来自两个来源的错误(检索描述错误的文本消息,或检查错误是否意味着“访问被拒绝”),它需要知道整型错误值的来源。为此,整型错误值需要伴随一条标识来源的信息。

Boost.System 提供了一个框架,使这成为可能。错误由类 `error_code` 表示,该类包含错误值和指向其来源(称为“类别”)的指针,表示为从 `error_category` 派生的类。

类别提供成员函数,例如 `message`,它返回特定错误值的文本消息,以及 `equivalent`,它可用于测试特定错误值是否对应于诸如“访问被拒绝”之类的错误条件。`error_code` 在其实现 `message` 和 `operator==` 成员函数时使用这些类别提供的函数。

Boost.System 包含两个预定义的类别类,通用类别(`generic_category()` 返回对其的引用)和系统类别(`system_category()`)。通用类别表示 POSIX 标准定义的 `errno` 值的可移植子集的错误值,而系统类别取决于操作系统。在 POSIX 下,系统类别表示操作系统 API 返回的 `errno` 值(通用类别中的值的超集),而在 Windows 下,系统类别表示 `GetLastError()` 返回的错误值。

该框架是可扩展的。用户可以通过从 `error_category` 派生一个类并实现一个返回对其实例的引用的函数来定义自己的类别。此功能对于描述库定义的错误值以及调整返回整型错误值的现有 C API 库都很有用。

对于那些喜欢通过异常报告错误的人,Boost.System 提供了一个标准异常类 `system_error`,它存储一个 `error_code`。

Boost.System 在 C++11 中被标准化为 `<system_error>`。一段时间以来,两者是等效的,但 Boost.System 自那时以来不断发展,现在包含对其标准兄弟的一些扩展

  • `message` 的非分配重载;

  • 通过 `failed` 成员函数支持非零错误代码表示成功;

  • 支持 64 位类别标识符,作为解决有时无法确保程序中只有一个类别实例的问题的方案;

  • 支持将源位置(文件/行/函数)附加到错误代码;

  • 一个类 `result<T>`,可用于从函数返回一个值或一个错误代码;

  • 各种其他小的改进。

`boost::system::error_code` 可以转换为 `std::error_code`,也可以从中构造。

用法

所有以下代码段都假定这些行

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

生效。

在 POSIX 下从操作系统 API 返回错误

假设我们正在实现操作系统文件 API 上的可移植 `file` 包装器。它的大致轮廓如下所示

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 );
};

由于我们正在实现 `file` 的 POSIX 版本,因此其数据成员是 POSIX 文件描述符 `int fd_;`,尽管其他实现会有所不同。

我们的 `read` 和 `write` 函数返回传输的字节数,并通过输出参数 `ec`(类型为 `boost::system::error_code`)发出错误信号。

`file::read` 的实现可能如下所示

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;
}

我们首先调用 POSIX API `read`;如果它返回错误,我们使用系统类别将 `errno` 值存储在 `ec` 中,并返回 0 作为传输的字节数。否则,我们清除 `ec` 以表示成功,并返回 `::read` 的结果。

注意
在成功返回时清除 `ec` 是一个重要步骤;不要省略它。

在 POSIX 下,系统类别对应于 POSIX `errno` 值,这就是我们使用它的原因。

原则上,由于通用类别*也*对应于所有平台下的 `errno` 值,我们也可以在这里使用它;但是,按照 POSIX 下的惯例,如果 `errno` 值来自操作系统(“系统”),我们对其使用系统类别。这是因为系统类别值可能是通用(平台无关)值的特定于平台的超集。

`file::write` 的实现基本相同。为了完整起见,我们在这里展示它

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;
}

在 Windows 下从操作系统 API 返回错误

在 Windows 下,我们的 `file` 对象将存储 `HANDLE` 而不是 `int`

class file
{
private:

    HANDLE fh_;

public:

    // as before
};

并且 `file::read` 的实现将如下所示

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;
}

这里,系统类别对应于系统头文件 `<winerror.h>` 中定义并由 `GetLastError()` 返回的值。由于我们使用 Win32 API `ReadFile` 来实现 `file::read`,并且它通过 `GetLastError()` 返回错误代码,我们再次将该值存储在 `ec` 中,作为属于系统类别。

`file::write` 的实现也是一样的。

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;
}

在 POSIX 下返回特定错误

我们对 `file::read` 的实现存在一个问题;它接受 `std::size_t` 值作为 `size`,但当请求的值不适合 `ssize_t` 时,`::read` 的行为未指定。为了避免依赖未指定的行为,让我们添加对此条件的检查并返回错误

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;
}

在这种情况下,由于我们返回的是固定的 `errno` 值 `EINVAL`,它是通用类别定义的可移植子集的一部分,因此我们将 `ec` 中的错误值标记为属于通用类别。

也可以使用 system,因为 `EINVAL` 也是 POSIX 下的系统类别值;但是,对于属于可移植 `errno` 子集的值使用通用类别稍微更好。

我们对 `file::write` 的实现需要进行类似的处理。但是,在那里,我们将应用另一个更改。当磁盘上没有剩余空间时,`::write` 返回的写入字节数低于我们使用 `size` 请求的字节数,但我们的函数没有发出错误信号。在这种情况下,我们将使其返回 `ENOSPC`。

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;
}

我们使用了系统类别,使其看起来 `ENOSPC` 值来自 `::write` API,主要是为了说明这也是一种可能的方法。使用通用值也可以同样奏效。

在 Windows 下返回特定错误

没什么好说的;Windows 下的情况完全相同。唯一的区别是我们*必须*使用通用类别来返回 `errno` 值。系统类别不起作用;系统类别中的整数值与通用类别中的整数值完全不同。

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;
}

将源位置附加到错误代码

与标准的 <system_error> 不同,Boost.System 允许将源代码位置(文件/行/函数)存储在 error_code 中,以便处理错误的函数可以显示或记录发生错误的源代码位置。为了利用此功能,我们的 POSIX file::read 函数需要进行如下扩充

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;
}

也就是说,在每个 ec.assign 语句之前,我们需要声明一个包含当前源代码位置的 static constexpr 变量,然后将指向它的指针传递给 assign。由于 error_code 很小,并且其中没有足够的空间来存储值,我们不能直接将 source_location 存储在其中。

BOOST_CURRENT_LOCATION 是一个扩展为当前源代码位置的宏(__FILE____LINE__BOOST_CURRENT_FUNCTION 的组合)。它在 Boost.Assert 中定义和记录。

在 C++03 下,需要使用 static const 而不是 static constexpr。另一种选择是 BOOST_STATIC_CONSTEXPR,这是一个 Boost.Config 宏,它会根据需要扩展为 static constexprstatic const

为了避免每次执行 ec.assign 时都重复这段样板代码,我们可以定义一个宏

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

现在我们可以使用它来扩充,例如,file::write 的 POSIX 实现

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;
}

获取错误代码的文本表示形式以进行日志记录和显示

假设我们有一个由某个函数返回的 error_code 实例 ec,我们有多种方法可以获取其中表示的错误代码的文本表示形式。

ec.to_string() 为我们提供了将 ec 流式传输到 std::ostream 的结果,例如,如果 std::cout << ec << std::endl; 输出 system:6,这就是 ec.to_string() 将返回的内容。(Windows 下的 system:6<winerror.h> 中的 ERROR_INVALID_HANDLE。)

要获取与此代码对应的可读错误消息,我们可以使用 ec.message()。对于 ERROR_INVALID_HANDLE,它会给我们“句柄无效” - 可能已本地化。

如果 ec 包含源代码位置,我们可以通过 ec.location().to_string() 获取其文本表示形式。这将给我们类似于

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

如果 ec 中存在位置,以及

(unknown source location)

如果不存在。(当 ec 包含位置时,ec.has_location()true。)

最后,ec.what() 将为我们提供一个包含所有上述内容的字符串,类似于

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 &)']

大多数不面向最终用户的日志记录和诊断输出可能会最终使用 what()。(使用构造时提供的`前缀` 增强的ec.what()也是`boost :: system :: system_error :: what()` 将返回的内容。)

组合返回错误代码的函数

假设我们需要实现一个文件复制函数,其接口如下

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

file_copy 使用 src.readsrc 读取字节,然后使用 dest.write 将这些字节写入 dest。这将持续到其中一个操作发出错误信号或到达文件末尾为止。它返回写入的字节数,并使用 ec 发出错误信号。

这是一种可能的实现方式

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;
    }
}

请注意,POSIX 和 Windows 实现之间不再有任何区别;它们的区别包含在 file::readfile::write 中。 file_copy 是可移植的,并且可以在任何平台下工作。

编写此类更高级别函数的一般模式是,它们将从调用者接收到的输出 error_code 参数 ec 直接作为输出参数传递给它们所基于的低级别函数。这样,当它们检测到中间操作失败(通过测试 ec.failed())时,它们可以立即返回给调用者,因为错误代码已位于正确的位置。

请注意,file_copy 甚至不需要在成功时使用 ec = {}; 清除 ec。由于我们已经测试了 ec.failed(),因此我们知道 ec 包含一个表示成功的值。

提供双重(抛出和不抛出)重载

通过输出 error_code& ec 参数发出错误信号的函数要求调用者在调用它们后检查 ec,并采取适当的操作(例如立即返回,如上所述)。忘记检查 ec会导致逻辑错误。

虽然这对于某些人来说是首选的编码风格,但其他人更喜欢异常,这是人们无法忘记检查的。

Boost.Filesystem(后来变成了 std::filesystem)引入的一种方法是提供两种选择:一个不抛出异常的函数,它接受 error_code& ec,如上面的 file_copy;一个抛出异常的函数,它不接受 error_code 输出参数,并在失败时抛出异常。

这是第二个抛出异常的函数的典型实现方式

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;
}

也就是说,我们只需调用 file_copy 的非抛出异常重载,如果它在 ec 中发出失败信号,则抛出一个 system_error 异常。

我们使用函数名 __func__ ("file_copy") 作为前缀,但这只是一个品味问题。

请注意,通常在这种风格下,接受 error_code& ec 的重载会使用 noexcept 进行修饰,以便清楚地表明它们不会抛出异常(尽管我们在前面的示例中没有这样做,是为了保持代码与 C++03 兼容)。

result<T> 作为双重 API 的替代方案

除了为每个操作提供两个函数之外,另一种方法是使函数返回 sys::result<T> 而不是 Tresult<T> 是一个持有 Terror_code 的类,类似于 variant<T, error_code>

喜欢检查错误而不依赖异常的客户端可以通过 if( r ) 或其更详细的等效项 if( r.has_value() ) 来测试 result<T> r 是否包含值,然后通过 *rr.value() 获取值。如果 r 不包含值,则可以使用 r.error() 获取它持有的 error_code

那些喜欢异常的人可以直接调用 r.value(),而无需检查。在没有值的情况下,这将自动抛出一个与 r 中的 error_code 对应的 system_error

假设我们的基本 file API 没有更改,则 file_copy 的此变体将如下所示

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;
    }
}

这里唯一的区别是我们在出错时返回 ec,而不是 r

但是请注意,我们不能再同时返回错误代码和传输的字节数;也就是说,我们不能再发出*部分成功*的信号。这在更高级别通常不是问题,但较低级别的原语(例如 file::readfile::write)最好使用旧样式编写。

不过,为了演示如何组合返回 result 的 API,我们将展示如果 file::readfile::write 返回 result<size_t>file_copy 将是什么样子

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;
    }
}

测试特定错误条件

假设我们调用了一个使用 error_code 发出失败信号的函数,我们向其传递了一个 error_code 变量 ec,现在由于某种原因要检查该函数是否因错误代码 EINVAL(“无效参数”)而失败。

由于可以比较 error_code 是否相等,因此我们的第一直觉可能是 if( ec == error_code( EINVAL, generic_category() ).

这是错误的,我们不应该这样做。

首先,在 POSIX 下,该函数可能已从系统类别返回 EINVAL(因为错误可能已由操作系统 API 返回,而不是由函数本身返回,如我们的 readwrite 实现中的情况)。

由于 error_code 比较是精确的,因此来自泛型类别的 EINVAL 与来自系统类别的 EINVAL 不相等。

(在你开始考虑仅将 ec.value()EINVAL 进行比较之前,请继续阅读。)

其次,在 Windows 下,该函数可能已返回 error_code( ERROR_INVALID_PARAMETER, system_category() )。正如我们已经提到的,Windows 下系统类别中的整数错误值与整数 errno 值完全无关。

正确的方法是将 ecerror_condition( EINVAL, generic_category() ) 进行比较,而不是与特定的错误代码进行比较。错误条件是以平台无关的方式表示具体错误代码含义的一种方法。在我们的例子中,在 POSIX 和 Windows 下,所有表示 EINVAL 的错误代码都将与 error_condition( EINVAL, generic_category() ) 相等。

简而言之,您永远不应该将错误代码与错误代码进行比较,而应该将它们与错误条件进行比较。这是 error_condition 类的用途,该类经常被误解。

由于

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

有点冗长,Boost.System 为可以直接与之比较错误代码的 errno 值提供了枚举器值。

这些枚举器在 <boost/system/errc.hpp> 中定义,并使上述测试能够写成

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

作为最佳实践,这通常应该用于测试特定错误条件。

调整现有的整型错误值

具有 C(或 extern "C")API 的库通常通过返回特定于库的整数错误代码来发出失败信号(零通常保留用于“无错误”)。在编写可移植的 C++ 包装器时,我们需要决定如何公开这些错误代码,使用 error_code 是一个好方法。

因为整数错误代码是特定于库的,并且通常与 errno 值或系统类别值都不匹配,所以我们需要定义一个特定于库的错误类别。

调整 SQLite 错误

我们将以 SQLite 为例。自定义错误类别的大致轮廓如下

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;
}

然后可以类似于预定义的泛型和系统类别使用它

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

如果我们尝试按原样编译上述类别定义,它将抱怨我们没有实现两个纯虚成员函数 namemessage,因此我们至少需要添加这些函数。此外,我们还将实现 message 的非分配重载。它不是纯虚拟的,但它的默认实现调用返回 std::string 的重载,而这几乎从来都不是人们想要的。(仅为了向后兼容性才提供此默认实现,以避免破坏在此重载添加之前编写的现有用户定义类别。)

因此,我们需要实现的最低限度是

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 很简单,它只返回类别名称

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

message 用于获取给定整数错误代码的错误消息。SQLite 提供了函数 sqlite3_errstr 来实现此目的,因此我们不需要做任何工作

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;
}

我们就完成了。 sqlite3_category() 现在可以像预定义的类别一样使用,我们可以通过 ec.assign( r, sqlite3_category() ) 将 SQLite 错误代码 int r 放入 Boost.System error_code ec 中。

调整 ZLib 错误

另一个广泛使用的 C 库是 ZLib,下面显示了定义其错误代码的 zlib.h 部分

#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.
 */

与之前的 SQLite 案例相比,存在三个相关的区别

  • 对于 SQLite,所有非零值都是错误,这是典型情况,而此处负值是错误,但正值是“特殊但正常”,也就是说,它们表示成功,而不是失败;

  • ZLib 不提供返回与特定错误代码对应的错误消息的函数;

  • 当返回 Z_ERRNO 时,应从 errno 检索错误代码。

我们的类别实现将如下所示

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;
}

像往常一样,name 的实现很简单

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

这次我们需要更加努力地实现 message,因为没有预先存在的函数可以依靠

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;
}

这是非抛出异常的 message 重载的典型实现。请注意,message 允许返回与 buffer 不同的内容,这意味着我们可以直接返回字符文字,而无需先将它们复制到提供的缓冲区中。这允许我们的函数即使在缓冲区太小时也能返回正确的消息文本。

现在 `message` 的 `std::string` 重载是平凡的(trivial)。

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

最后,我们需要实现 `failed`,以覆盖其默认行为,即对所有非零值返回 `true`。

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

这完成了 `zlib_category()` 的实现,并处理了上面列出的前两点,但我们还没有解决第三点;即,我们需要在 `Z_ERRNO` 的情况下从 `errno` 中检索错误。

为此,我们将定义一个辅助函数,用于将 ZLib 错误代码分配给 `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() );
    }
}

这样,代码将使用以下方式,而不是直接使用 `ec.assign( r, zlib_category() )`:

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

我们可以就此止步,因为这涵盖了我们着手做的所有事情,但我们可以更进一步,为我们的错误代码启用源位置。为此,我们需要更改 `assign_zlib_error` 以接受 `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 );
    }
}

定义一个辅助宏,以避免每次都定义 `static constexpr` 源位置对象的样板代码。

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

然后使用宏代替函数。

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

支持与条件的比较

我们注意到,一些 ZLib 错误代码对应于可移植的 `errno` 条件。例如,`Z_STREAM_ERROR` 在 POSIX 函数返回 `EINVAL` 的情况下返回;`Z_MEM_ERROR` 是 `ENOMEM`;`Z_BUF_ERROR`,输出缓冲区中没有足够的空间来存储结果,大致对应于 `ERANGE`,结果超出范围。

为了编码这种关系,我们需要在我们的类别中实现 `default_error_condition` 或 `equivalent`。由于我们有一个简单的一对一映射,前者就足够了。

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;
};

实现很简单。

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 );
}

添加此功能后,我们将能够将 ZLib `error_code ec` 与 `errc` 枚举器进行比较。

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

定义库特定的错误代码

假设我们正在编写一个库 `libmyimg` 来读取某种假设的图像格式,并且我们已经为此定义了以下 API 函数:

namespace libmyimg
{

struct image;

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

} // namespace libmyimg

(使用前面示例中的可移植 `file` 类。)

我们假设的图像格式很简单,由一个固定的标头和图像数据组成,因此 `load_image` 的实现可能具有以下结构:

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

我们可以看到,我们需要自己定义五个错误代码。(我们的函数也可以在 `ec` 中返回其他类型的失败 - 这些失败将来自 `load_image_header` 将用于读取标头的 `file::read`。)

为了定义这些错误,我们将使用一个作用域枚举类型。(此示例将利用 C++11 功能。)

namespace libmyimg
{

enum class error
{
    success = 0,

    invalid_signature,
    invalid_width,
    invalid_height,
    unsupported_bit_depth,
    unsupported_channel_count
};

} // namespace libmyimg

Boost.System 支持告知枚举类型表示错误代码,这使得枚举类型和 `error_code` 之间可以进行隐式转换。这是通过特化 `is_error_code_enum` 类型特征来完成的,该特征与库的其余部分一样位于 `namespace boost::system` 中。

namespace boost
{
namespace system
{

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

} // namespace system
} // namespace boost

一旦到位,我们现在就可以将 `libmyimg::error` 的值分配给 `sys::error_code`,这使得 `load_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 )
    {
        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

    // ...
}

然而,这还不够;我们仍然需要为我们的枚举器定义错误类别,并将它们与其关联。

第一步与我们之前的两个示例非常相似。

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

第二步涉及在枚举类型 `error` 的命名空间中实现一个函数 `make_error_code`,该函数接受 `error` 并返回 `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

现在 `load_image` 将编译,我们只需要用使用 `file::read` 读取图像数据的代码填充其剩余的实现。

还有一个额外的修饰我们可以做。众所周知,Boost.System 被提议并被 C++11 标准接受,现在在 `<system_error>` 中有一个标准实现。我们也可以通过特化标准类型特征 `std::is_error_code_enum` 使我们的错误枚举类型与 `std::error_code` 兼容。

namespace std
{

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

} // namespace std

这使得我们的枚举器可以转换为 `std::error_code`。

(之所以可行,是因为 `boost::system::error_code` 可以转换为 `std::error_code`,因此我们的 `make_error_code` 重载的返回值可以用来初始化 `std::error_code`。)

定义库特定的错误条件

到目前为止,我们所有的 `libmyimg::error` 错误代码都表示相同的错误情况 - 无效或不支持的图像格式。可以在无需枚举所有五个特定代码的情况下启用对此条件的测试。为此,我们可以定义一个错误条件枚举类型。

namespace libmyimg
{

enum class condition
{
    invalid_format = 1
};

} // namespace libmyimg

我们可以通过特化 `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

与需要 `make_error_code` 重载的错误代码枚举类型类似,这个类型将需要一个 `make_error_condition` 重载和一个类别。

原则上可以通过使条件值从 10000 而不是 1 开始来重用我们已经为错误代码定义的类别。这可以节省一些输入,但更好的做法是为错误条件使用单独的类别。所以这就是我们要做的。

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

我们有条件,但它还没有做任何事情。为了使 `libmyimg::condition::invalid_format` 能够与我们的错误代码进行比较,我们需要在错误代码类别中实现 `default_error_condition`。

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

就是这样;现在 `ec == libmyimg::condition::invalid_format` 可以用来测试 `ec` 是否包含对应于“无效图像格式”条件的错误代码之一。

修订历史

Boost 1.86 中的更改

  • 支持 `result<T> & fv`,其中 `fv` 返回 `void`。

  • 支持 `result<void> &= fv;`,其中 `fv` 返回 `void`。

Boost 1.85 中的更改

  • 不再支持 C++03;需要 C++11 编译器。(这包括 GCC 4.8 或更高版本,以及 MSVC 14.0 (VS 2015) 或更高版本。)

  • 已删除已弃用的标头 `boost/system/cygwin_error.hpp`。

  • 不再支持原始的和过时的(32 位)MinGW。仍然支持 MinGW-w64(64 位和 32 位)。

  • `operator&` 现在适用于 `result<void>`(通过接受空函数的方式)。

  • 为 `result` 添加了 `operator|=`。

Boost 1.84 中的更改

  • 添加了对 `result<U&, E>` 的支持。

  • 为 `result` 添加了 `operator|`。

  • 为 `result` 添加了 `operator&`。

  • 为 `result` 添加了 `operator&=`。

Boost 1.81 中的更改

  • 现在可以定义宏 `BOOST_SYSTEM_DISABLE_THREADS` 来禁用 `<mutex>` 的使用(例如,在单线程 libstdc++ 上)。

  • 向 `result<>` 添加了 `value_type`、`error_type`、`in_place_value`、`in_place_error`。

  • 向 `result<>` 添加了 `emplace`。

Boost 1.80 中的更改

  • 当 `error_code` 转换为 `std::error_code` 然后再转换回 `error_code` 时,如果可能,现在将恢复原始值。

  • 重新设计了从 `error_category` 到 `std::error_category` 的转换,以避免泄漏检查器上出现的一次性分配。

  • 添加了一个构造函数,允许替换 `error_code` 的源位置,以及相应的 `assign`。

  • 向 `result` 添加了一个转换构造函数。

Boost 1.79 中的更改

  • 向 `throw_exception_from_error` 添加了一个 `boost::source_location` 参数。

  • 为 `errc::errc_t`、`std::error_code`、`std::errc`、`std::exception_ptr` 添加了 `throw_exception_from_error` 重载。

  • `result<T>::value` 现在通过默认参数自动向 `throw_exception_from_error` 提供 `BOOST_CURRENT_LOCATION`。

  • 添加了一个接受源位置的 `errc::make_error_code` 重载。

Boost 1.78 中的更改

  • 向 `error_code` 添加了对源位置的支持。

  • 添加了 `error_code::to_string`、`error_condition::to_string`、`error_code::what`。

  • `system_error::what()` 现在包含源位置(如果存在)。

  • 添加了 `result<T, E = error_code>`,一个持有值或错误的类,在 `<boost/system/result.hpp>` 中定义。

Boost 1.77 中的更改

  • 从 `error_category` 到 `std::error_category` 的转换运算符已得到改进,不再需要 `<map>` 或 `<mutex>`。

  • `error_category` 的比较运算符现在是内联友元而不是成员函数(前一个更改的副作用)。

  • `error_condition` 现在推迟调用 `generic_category()` 以避免实例化对象,直到实际需要它为止。

  • `error_condition::failed` 和 `error_condition::message` 已取消弃用,`operator bool()` 现在再次返回 `failed()`。

  • 系统类别现在不调用 `generic_category()`,以避免实例化对象。

  • 在某些情况下,`default_error_condition` 的返回值会更改为来自泛型类别的 `error_condition`,而不是来自系统类别的 `error_condition`。当输入 `error_code` 来自系统类别并且不对应于任何 `errc_t` 值时,这种情况会在 POSIX 上发生。

  • `error_code` 和 `std::error_code` 的互操作性已得到显着改进。现在可以从 `std::error_code` 构造 `boost::system::error_code`,并且可以将 `boost::system::error_code` 传递给接受 `std::error_code&` 的函数。

  • 添加了 `error_condition` 的流插入运算符。

Boost 1.76 中的更改

  • `windows_error.hpp` 不再被弃用。

Boost 1.75 中的更改

  • 特定于平台的标头 `windows_error.hpp`、`linux_error.hpp` 和 `cygwin_error.hpp` 会发出弃用消息,并计划删除。

  • `generic_category()` 和 `system_category()` 的旧名称会发出弃用消息,并计划删除。

  • `error_condition::failed` 已弃用,并计划删除。`error_condition` 的 `operator bool()` 已恢复其旧含义 `value() != 0`。这样做是为了与 `std::error_condition` 兼容,因为下一个版本预计将进一步改进与 `<system_error>` 的互操作性。*请注意,这不会影响* `error_code::failed`,它仍然有效。

  • 出于同样的原因,接受缓冲区的 `error_condition::message` 重载已弃用,并计划删除。*请注意,这不会影响* `error_code::message`。

Boost 1.74 中的更改

  • `operator bool()` 现在返回 `failed()` 而不是 `value() != 0`。

Boost 1.69 中的更改

  • Boost.System 现在是仅限标头的。为了兼容性,仍然构建了一个存根库,但不再需要链接到它。

  • 更多函数已被标记为 `constexpr`。

  • `error_category` 的析构函数现在受保护,不再是虚函数。这是一个*潜在的重大更改*,但其影响预计有限。

  • `error_category` 现在有一个接受 64 位标识符的构造函数,允许不同的类别对象比较相等。

  • `error_category` 的构造函数现在受保护。

  • 添加了一个非分配、非抛出的 `message` 重载。

  • 添加了一个虚函数 `failed`,允许类别成功不等于 0。

  • 已弃用的 boost::system::throws 对象已被移除。

  • boost::throws() 现已弃用,不建议使用。

  • system_error 的构造函数,采用单个 error_code 参数,现在为显式构造函数。

  • system_error::code() 现在按值返回。

Boost 1.68 中的更改

在 C++14 编译器上,许多 Boost.System 函数和成员函数现在是 constexpr,并且 error_codeerror_condition 是字面类。

除了能够在常量表达式(和 constexpr 函数)中使用之外,这还显著提高了生成的代码的质量。

然而,由于此更改,现在从 C++14 或 C++17 代码使用 Boost.System 要求该库也使用 C++14 或更高版本构建。这是 GCC 6 及更高版本的默认设置,但 GCC 5 或 Clang 不是。可以通过将 cxxstd=14 选项传递给 b2 来构建 C++14 的 Boost。

(以前的版本允许针对任何 C++ 标准构建的代码与针对任何 C++ 标准构建的 Boost.System 链接。在 1.68 中,使用任何 C++ 标准的代码可以与使用 C++14 或更高版本构建的 Boost.System 链接,但如果 Boost.System 使用 C++11 或更低版本构建,则只有使用 C++11 及更低版本构建的代码才能成功链接到它。)

Boost 1.65 中的更改

在 C++11 编译器上,Boost.System 现在提供从 boost::system::error_categoryerror_codeerror_condition 到它们在 <system_error> 中的标准等效物的隐式转换。

这允许库公开 C++11 接口并通过 std::error_code 报告错误,即使使用 Boost.System(直接或通过依赖项(例如 Boost.ASIO))。

设计原理

error_codeerror_condition 被设计为值类型,因此它们可以在不发生切割的情况下进行复制,并且不需要堆分配,但仍然具有基于错误类别的多态行为。这是通过抽象基类 error_category 提供多态行为,以及 error_codeerror_condition 包含指向从 error_category 派生的类型的对象的指针来实现的。

许多详细的设计决策都是由用户能够添加其他错误类别以及编写可移植代码不比编写系统特定代码更难的要求驱动的。

error_codeoperator<< 重载消除了在诸如 cout << ec 之类的代码中将 ec 转换为 bool 的误导性转换,其中 ec 的类型为 error_code。它本身也很有用。

参考

当定义 BOOST_SYSTEM_ENABLE_DEPRECATED 时,该库提供已弃用的功能以实现兼容性。这些功能最终将会消失。

当定义 BOOST_SYSTEM_USE_UTF8 时,在 Windows 上,该库使用代码页 CP_UTF8 而不是默认的 CP_ACP 返回 UTF-8 消息。此宏对 POSIX 没有影响。

当定义 BOOST_SYSTEM_DISABLE_THREADS 时,该库假定当前平台不支持多线程并禁用标准头文件 <mutex> 的使用,从而消除了互斥锁。单线程 libstdc++ 就是这样一个平台。

已弃用的名称

在将 Boost.System 添加到 C++11 标准库的过程中,C++ 委员会更改了一些名称。为了简化转换,Boost.System 弃用了旧名称,但在定义宏 BOOST_SYSTEM_ENABLE_DEPRECATED 时将提供它们。

旧用法,现已弃用 替换

get_generic_category()

generic_category()

get_system_category()

system_category()

命名空间 posix

命名空间 errc

命名空间 posix_error

命名空间 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

用户可以为其错误枚举类型专门化 is_error_code_enum,以指示它们应该有资格自动转换为 error_code。此转换调用 make_error_code(e),该函数应在与枚举类型相同的命名空间中提供。

<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

用户可以为其错误枚举类型专门化 is_error_condition_enum,以指示它们应该有资格自动转换为 error_condition。此转换调用 make_error_condition(e),该函数应在与枚举类型相同的命名空间中提供。

<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

预定义的枚举类型 errc::errc_t 提供了与 <cerrno> 宏的值对应的命名常量。

constexpr error_condition make_error_condition( errc::errc_t e ) noexcept;
  • 返回值

    error_condition( e, generic_category() ).

    由于 errc::errc_t 提供了 is_error_condition_enum 的特化和 make_error_condition 的重载,因此它可以隐式转换为 error_condition。这通常在将从 API 返回的 error_code 值与可移植条件进行比较时很有用,如下例所示

  • 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;
  • 返回值

    error_code( e, generic_category() ).

    除了 make_error_condition 之外,errc::errc_t 还提供了 make_error_code 的重载。这允许创建通用错误代码,当函数需要 segnal 来自底层 API 的通用故障时(例如内存不足情况),此操作通常很有用

  • 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;
  • 返回值

    error_code( e, generic_category(), loc ).

    与上述重载相同,但采用源位置。

  • 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

error_category 定义了用于标识特定错误代码类别来源和编码的类型的基类。

可以从 error_category 派生类以支持除 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
构造函数
constexpr error_category() noexcept;
  • 效果

    id_ 初始化为 0。

    备注

    由于没有标识符的类别的等效性基于比较对象地址,因此使用此构造函数的类型为 C 的用户定义派生类别应确保程序中只有一个类型为 C 的对象存在。

explicit constexpr error_category( unsigned long long id ) noexcept;
  • 效果

    id_ 初始化为 id

    备注

    当标识符匹配时,使用此构造函数的用户定义派生类别被认为是等效的。因此,这些类别可能在程序中存在多个实例,但为了最大限度地减少冲突的可能性,它们的标识符必须随机选择(在实现类别时,而不是在运行时)。生成 64 位随机标识符的一种方法是 https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h

虚函数
virtual const char * name() const noexcept = 0;
  • 返回值

    在派生类中,命名错误类别的字符字面量。

virtual error_condition default_error_condition( int ev ) const noexcept;
  • 返回值
    • 在派生类中,对应于 ev 的错误条件。返回的错误条件通常来自通用类别。

    • 在默认实现中,error_condition( ev, *this )

virtual bool equivalent( int code, const error_condition & condition )
  const noexcept;
  • 返回值
    • 在派生类中,当 error_code( code, *this ) 等效于 `condition` 时为 `true`。

    • 在默认实现中,`default_error_condition( code ) == condition`。

virtual bool equivalent( const error_code & code, int condition )
  const noexcept;
  • 返回值
    • 在派生类中,当 `code` 等效于 `error_condition( condition, *this )` 时为 `true`。

    • 在默认实现中,`*this == code.category() && code.value() == condition`。

virtual std::string message( int ev ) const = 0;
  • 返回值

    在派生类中,描述由 `ev` 表示的错误的字符串。

virtual char const * message( int ev, char * buffer, std::size_t len )
  const noexcept;
  • 效果
    • 派生类应该

      • 返回指向描述由 `ev` 表示的错误的字符字面量的指针,或者

      • 将描述错误的字符串复制到 `buffer` 中,将其截断为 `len-1` 个字符并存储一个空终止符,然后返回 `buffer`。如果 `len` 为 0,则不复制任何内容,但函数仍返回 `buffer`。请注意,当 `len` 为 0 时,`buffer` 可能为 `nullptr`。

    • 默认实现调用 `message(ev)` 并将结果复制到 `buffer` 中,将其截断为 `len-1` 个字符并存储一个空终止符。如果 `len` 为 0,则不复制任何内容。返回 `buffer`。如果 `message(ev)` 抛出异常,则使用字符串“Message text unavailable(消息文本不可用)”。

    示例
    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;
  • 返回值
    • 在派生类中,当 `ev` 表示失败时为 `true`。

    • 在默认实现中,`ev != 0`。

    备注

    使用相同 `ev` 对此函数的所有调用必须返回相同的值。

比较
friend constexpr bool operator==( const error_category & lhs,
  const error_category & rhs ) noexcept;
  • 返回值

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

    备注

    当两个类别对象具有匹配的非零标识符或为同一对象时,它们被认为是等效的。

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

    !( lhs == rhs ).

constexpr bool operator< ( const error_category & lhs,
  const error_category & rhs ) const noexcept;
  • 返回值
    • 如果 `lhs.id_ < rhs.id_`,则为 `true`;

    • 否则,如果 `lhs.id_ > rhs.id_`,则为 `false`;

    • 否则,如果 `rhs.id_ != 0`,则为 `false`;

    • 否则,`std::less<error_category const *>()( &lhs, &rhs )`。

转换
operator std::error_category const & () const;
  • 返回值

    对与 `*this` 对应的 `std::error_category` 对象的引用。

<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;
  • 返回值

    对预定义的 `error_category` 对象的引用,该对象标识源自操作系统的错误。

<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;
  • 返回值

    对预定义的 `error_category` 对象的引用,该对象标识可移植错误代码和条件。

<boost/system/​error_code.hpp>

error_code

类 `error_code` 描述了用于保存错误代码值的对象,例如源自操作系统或其他低级应用程序接口的错误代码值。它是通过异常进行错误报告的补充。

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
构造函数
constexpr error_code() noexcept;
  • 确保

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

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

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

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

    `loc` 指向具有静态存储期的有效 `boost::source_location` 对象。

    确保

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

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

    *this == make_error_code( e ).

    备注

    仅当 `is_error_code_enum<ErrorCodeEnum>::value` 为 `true` 时,才启用此构造函数。

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

    `loc` 指向具有静态存储期的有效 `boost::source_location` 对象,或者为 `nullptr`。

    确保

    *this == ec.

    备注

    当 `ec` 是默认构造的 `error_code` 或包装 `std::error_code` 时,或者当 `loc` 为 `nullptr` 时,`*this` 不存储位置(`has_location()` 为 `false`)。否则,`*this` 存储 `loc`(`has_location()` 为 `true` 且 `&location()` 为 `loc`。)

error_code( std::error_code const & ec ) noexcept;
  • 效果

    构造一个包装 `ec` 的 `error_code`。

    备注

    `value()` 和 `category()` 未指定。`has_location()` 为 `false`。

修饰符
constexpr void assign( int val, const error_category & cat ) noexcept;
  • 效果

    *this = error_code( val, cat ).

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

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

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

    *this == make_error_code( e ).

    备注

    仅当 `is_error_code_enum<ErrorCodeEnum>::value` 为 `true` 时,才启用此运算符。

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

    *this = error_code( ec, loc ).

constexpr void clear() noexcept;
  • 效果

    *this = error_code().

观察者
constexpr int value() const noexcept;
  • 返回值

    错误值。

constexpr const error_category & category() const noexcept;
  • 返回值

    错误类别。

error_condition default_error_condition() const noexcept;
  • 返回值

    category().default_error_condition( value() ).

std::string message() const;
  • 返回值

    如果 `*this` 包装 `std::error_code` 对象 `ec`,则为 `ec.message()`。否则,为 `category().message( value() )`。

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

    如果 `*this` 包装 `std::error_code` 对象 `ec`,则将从 `ec.message()` 返回的字符串复制到 `buffer` 中并返回 `buffer`。否则,返回 `category().message( value(), buffer, len )`。

constexpr bool failed() const noexcept;
  • 返回值

    如果 `*this` 包装 `std::error_code` 对象 `ec`,则为 `ec.value() != 0`。否则,为 `category().failed( value() )`。

constexpr explicit operator bool() const noexcept;
  • 返回值

    failed().

bool has_location() const noexcept;
  • 返回值

    如果 `*this` 已使用指向源位置的指针构造,则为 `true`,否则为 `false`。

boost::source_location const & location() const noexcept;
  • 返回值

    如果 `*this` 已使用指向源位置 `loc` 的指针构造,则为 `*loc`,否则为对默认构造的 `boost::source_location` 的引用。

比较
friend constexpr bool operator==( const error_code & lhs,
  const error_code & rhs ) noexcept;
  • 返回值

    如果 `lhs` 和 `rhs` 都包装 `std::error_code` 对象 `e1` 和 `e2`,则为 `e1 == e2`。否则,为 `lhs.value() == rhs.value() && lhs.category() == rhs.category()`。

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

    !( lhs == rhs ).

friend constexpr bool operator<( const error_code & lhs,
  const error_code & rhs ) noexcept;
  • 返回值

    如果 `lhs` 和 `rhs` 都包装 `std::error_code` 对象 `e1` 和 `e2`,则为 `e1 < e2`。否则,为 `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;
  • 返回值

    如果 `code` 包装 `std::error_code` 对象 `ec`,则为 `ec == static_cast<std::error_condition>( condition )`。否则,为 `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;
  • 返回值

    !( lhs == rhs ).

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

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

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

    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;
  • 返回值

    !( lhs == rhs ).

template<class E>
  friend constexpr bool operator==( const error_code & lhs, E rhs ) noexcept;
  • 效果
    • 当 `is_error_code_enum<E>::value` 为 `true` 时,返回 `lhs == make_error_code(rhs)`;

    • 当 `is_error_condition_enum<E>::value` 为 `true` 时,返回 `lhs == make_error_condition(rhs)`;

    • 否则,将禁用此重载。

template<class E>
  friend constexpr bool operator==( E lhs, const error_code & rhs ) noexcept;
  • 效果
    • 当 `is_error_code_enum<E>::value` 为 `true` 时,返回 `make_error_code(lhs) == rhs`;

    • 当 `is_error_condition_enum<E>::value` 为 `true` 时,返回 `make_error_condition(lhs) == rhs`;

    • 否则,将禁用此重载。

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;
  • 返回值

    !( lhs == rhs ).

    备注

    仅当 `is_error_code_enum<E>::value` 为 `true` 或 `is_error_condition_enum<E>::value` 为 `true` 时,才启用这些重载。

转换
operator std::error_code() const;
operator std::error_code();
  • 返回值

    如果 *this 包装了一个 std::error_code 对象 ec,则返回 ec。否则,返回 std::error_code( value(), category() )

template<class T> operator T&();
  • 效果

    如果 *this 包装了一个 std::error_code 对象 ec,则返回对 ec 的引用。否则,使 *this 包装 std::error_code( *this ),然后返回对它的引用。

    备注

    仅当 Tstd::error_code 时,此运算符才启用。

to_string
std::string to_string() const;
  • 返回值

    如果 *this 包装了一个 std::error_code 对象 e2,则返回一个字符串,该字符串是 "std:"e2.category().name()':'e2.value() 的字符串表示形式的连接。否则,返回 category().name()':'value() 的字符串表示形式的连接。

流插入
template <class charT, class traits>
  std::basic_ostream<charT, traits>&
    operator<<( basic_ostream<charT, traits>& os, const error_code & ec );
  • 效果

    os << to_string().

    返回值

    os.

what
std::string what() const;
  • 返回值

    *this 的字符串表示形式,适用于日志记录和诊断输出。通常包含 message()to_string()location().to_string()(如果可用)。

非成员函数
std::size_t hash_value( const error_code & ec );
  • 返回值

    如果 ec 包装了一个 std::error_code 对象 e2,则返回 std::hash<std::error_code>()(e2)。否则,返回表示 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
构造函数
constexpr error_condition() noexcept;
  • 确保

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

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

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

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

    *this == make_error_condition( e ).

    备注

    仅当 is_error_condition_enum<ErrorConditionEnum>::valuetrue 时,此构造函数才启用。

修饰符
constexpr void assign( int val, const error_category & cat ) noexcept;
  • 确保

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

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

    *this == make_error_condition( e ).

    备注

    仅当 is_error_condition_enum<ErrorConditionEnum>::valuetrue 时,此运算符才启用。

constexpr void clear() noexcept;
  • 确保

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

观察者
constexpr int value() const noexcept;
  • 返回值

    错误值。

constexpr const error_category & category() const noexcept;
  • 返回值

    错误类别。

std::string message() const;
  • 返回值

    category().message( value() ).

char const * message( char * buffer, std::size_t len ) const noexcept;
  • 返回值

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

constexpr bool failed() const noexcept;
  • 返回值

    category().failed( value() ).

constexpr explicit operator bool() const noexcept;
  • 返回值

    failed().

比较
friend constexpr bool operator==( const error_condition & lhs,
  const error_condition & rhs ) noexcept;
  • 返回值

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

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

    !( lhs == rhs ).

friend constexpr bool operator<( const error_condition & lhs,
  const error_condition & rhs ) noexcept;
  • 返回值

    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;
  • 返回值

    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;
  • 返回值

    !( lhs == rhs ).

转换
operator std::error_condition() const;
  • 返回值

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

to_string
std::string to_string() const;
  • 返回值

    "cond:"category().name()':'value() 的字符串表示形式的连接。

流插入
template <class charT, class traits>
  std::basic_ostream<charT, traits>&
    operator<<( basic_ostream<charT, traits>& os, const error_condition & en );
  • 效果

    os << en.to_string().

    返回值

    os.

<boost/system/​system_error.hpp>

system_error

system_error 描述了一个异常对象,用于报告具有关联 error_code 的错误。此类错误通常源于操作系统或其他低级应用程序接口。

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
构造函数
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 );
  • 确保

    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 );
  • 确保

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

观察者
error_code code() const noexcept;
  • 返回值

    根据构造函数,返回 ecerror_code( ev, ecat )

const char * what() const noexcept;
  • 返回值

    一个以 null 结尾的字符串,包含构造函数中提供的参数,通常格式为 what_arg + ": " + code().message()

<boost/system/result.hpp>

此头文件定义了类模板 result<T, E>。与库的其余部分不同,它需要 C++11。

概要

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

当结果包含错误时,函数 throw_exception_from_errorresult<T, E>::value() 调用。其目的是抛出一个表示结果中包含的错误的异常。

已经为 Eerror_code 的常见和默认情况提供了实现。它抛出 system_error(e)

如果 result<T, E> 与其他错误类型一起使用,则用户应在 E 的命名空间中提供 throw_exception_from_error 的适当重载。

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

    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 );
  • 效果

    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 );
  • 效果

    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 );
  • 效果

    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 );
  • 效果
    • 如果 e 不为空,则 std::rethrow_exception( e )

    • 否则,boost::throw_with_location( std::bad_exception(), loc )

result<T, E>

result<T, E> 存储类型 T 的值或类型 E 的错误。E 默认为 error_code。在典型用法中,可能失败的函数返回 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
构造函数
constexpr result();
  • 确保

    *this 包含值 T()

    备注

    仅当 std::is_default_constructible<T>::valuetrue 时,此构造函数才启用。

template<class... A>
  constexpr result( A&&... a );
  • 效果
    • 如果 std::is_constructible<T, A…​>::value && !std::is_constructible<E, A…​>::value,则确保 *this 包含值 T( std::forward<A>(a)…​ )

    • 如果 `std::is_constructible<E, A…​>::value && !std::is_constructible<T, A…​>::value`,则确保 `*this` 包含错误 `E( std::forward<A>(a)…​ )`。

    • 否则,此构造函数不参与重载决议。

    备注

    仅当 sizeof…​(A) > 0 时,此构造函数才启用。

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

    *this 包含值 T( std::forward<A>(a)…​ )

    备注

    仅当 std::is_constructible<T, A…​>::valuetrue 时,此构造函数才启用。

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

    *this 包含错误 E( std::forward<A>(a)…​ )

    备注

    仅当 std::is_constructible<E, A…​>::valuetrue 时,此构造函数才启用。

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

    如果 r2.has_value()true,则 *this 包含值 T( *r2 ),否则 *this 包含错误 E( r2.error() )

    备注

    仅当 std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::valuetrue 时,此构造函数才启用。

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

    如果 r2.has_value()true,则 *this 包含值 T( std::move( *r2 ) ),否则 *this 包含错误 E( r2.error() )

    备注

    仅当 std::is_convertible<T2, T>::value && std::is_convertible<E2, E>::valuetrue 时,此构造函数才启用。

查询
constexpr bool has_value() const noexcept;
  • 返回值

    *this 包含值时为 true,否则为 false

constexpr bool has_error() const noexcept;
  • 返回值

    !has_value().

constexpr explicit operator bool() const noexcept;
  • 返回值

    has_value().

已检查值访问
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&& ;
  • 效果

    如果 *this 包含值,则返回对它的引用。否则,调用 throw_exception_from_error,并向其传递对所包含错误的引用和 loc

未检查值访问
constexpr T* operator->() noexcept;
constexpr T const* operator->() const noexcept;
  • 返回值

    如果 *this 包含值,则返回指向它的指针。否则,返回 nullptr

constexpr T& operator*() & noexcept;
constexpr T const& operator*() const & noexcept;
  • 要求

    *this 包含一个值。

    返回值

    *operator->().

constexpr T&& operator*() && noexcept;
constexpr T const&& operator*() const && noexcept;
  • 要求

    *this 包含一个值。

    返回值

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

错误访问
constexpr E error() const &;
constexpr E error() &&;
  • 效果

    如果 *this 包含错误,则返回它。否则,返回 E()

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

    *this 包含值 T( std::forward<A>(a)…​ )

    返回值

    对所包含值的引用。

swap
constexpr void swap( result& r );
  • 效果

    交换 *thisr 的内容。

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

    交换 r1r2 的内容。

相等性
friend constexpr bool operator==( result const & r1, result const & r2 );
  • 效果
    • 如果 r1 包含值 t1r2 包含值 t2,则返回 t1 == t2

    • 如果 r1 包含错误 e1r2 包含错误 e2,则返回 e1 == e2

    • 否则,返回 false

friend constexpr bool operator!=( result const & r1, result const & r2 );
  • 返回值

    !( r1 == r2 ).

流插入
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 );
  • 效果
    • 如果 *this 包含值 t,则 os << "value:" << t

    • 如果 *this 包含错误 e,则 os << "error:" << e

    返回值

    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
构造函数
constexpr result() noexcept;
  • 确保

    *this 包含一个未指定的值。

template<class... A>
  constexpr result( A&&... a );
  • 效果
    • 如果 std::is_constructible<E, A…​>::value,则确保 *this 包含错误 E( std::forward<A>(a)…​ )

    • 否则,此构造函数不参与重载决议。

    备注

    仅当 sizeof…​(A) > 0 时,此构造函数才启用。

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

    *this 包含一个未指定的值。

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

    *this 包含错误 E( std::forward<A>(a)…​ )

    备注

    仅当 std::is_constructible<E, A…​>::valuetrue 时,此构造函数才启用。

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

    如果 r2.has_value()true,则 *this 包含一个未指定的值,否则 *this 包含错误 E( r2.error() )

    备注

    仅当 std::is_convertible<E2, E>::valuetrue 时,此构造函数才启用。

查询
constexpr bool has_value() const noexcept;
  • 返回值

    *this 包含值时为 true,否则为 false

constexpr bool has_error() const noexcept;
  • 返回值

    !has_value().

constexpr explicit operator bool() const noexcept;
  • 返回值

    has_value().

已检查值访问
constexpr void value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;
  • 效果

    如果 *this 不包含值,则调用 throw_exception_from_error,并向其传递对所包含错误的引用和 loc

未检查值访问
constexpr void* operator->() noexcept;
constexpr void const* operator->() const noexcept;
  • 返回值

    如果 *this 包含值,则返回指向它的指针。否则,返回 nullptr

constexpr void operator*() const noexcept;
  • 要求

    *this 包含一个值。

    效果

    无。

错误访问
constexpr E error() const &;
constexpr E error() &&;
  • 效果

    如果 *this 包含错误,则返回它。否则,返回 E()

emplace
constexpr void emplace();
  • 确保

    *this 包含一个未指定的值。

swap
constexpr void swap( result& r );
  • 效果

    交换 *thisr 的内容。

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

    交换 r1r2 的内容。

相等性
friend constexpr bool operator==( result const & r1, result const & r2 );
  • 效果
    • 如果 r1r2 包含值,则返回 true

    • 如果 r1 包含错误 e1r2 包含错误 e2,则返回 e1 == e2

    • 否则,返回 false

friend constexpr bool operator!=( result const & r1, result const & r2 );
  • 返回值

    !( r1 == r2 ).

流插入
template<class Ch, class Tr, class E>
  std::basic_ostream<Ch, Tr>&
    operator<<( std::basic_ostream<Ch, Tr>& os, result<void, E> const & r );
  • 效果
    • 如果 *this 包含一个值,则 os << "value:void"

    • 如果 *this 包含错误 e,则 os << "error:" << e

    返回值

    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
构造函数
template<class A>
  constexpr result( A&& a ) noexcept;
  • 确保

    *this 包含引用 static_cast<U&>( std::forward<A>(a) )

    备注

    仅当 AB&std::is_convertible<B*, U*>::valuetrue 时,此构造函数才启用。

template<class... A>
  constexpr result( A&&... a );
  • 效果
    • 如果 `std::is_constructible<E, A…​>::value && !std::is_constructible<U&, A…​>::value`,则确保 `*this` 包含错误 `E( std::forward<A>(a)…​ )`。

    • 否则,此构造函数不参与重载决议。

    备注

    仅当 sizeof…​(A) > 0 时,此构造函数才启用。

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

    *this 包含引用 static_cast<U&>( std::forward<A>(a) )

    备注

    仅当 AB&std::is_convertible<B*, U*>::valuetrue 时,此构造函数才启用。

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

    *this 包含错误 E( std::forward<A>(a)…​ )

    备注

    仅当 std::is_constructible<E, A…​>::valuetrue 时,此构造函数才启用。

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

    如果 r2.has_value()true,则 *this 包含引用 `static_cast<U&>( *r2 )`,否则 `*this` 包含错误 `E( r2.error() )`。

    备注

    仅当 `std::is_convertible<U2*, U*>::value && std::is_convertible<E2, E>::value` 为 `true` 时,此构造函数才启用。

查询
constexpr bool has_value() const noexcept;
  • 返回值

    *this 包含值时为 true,否则为 false

constexpr bool has_error() const noexcept;
  • 返回值

    !has_value().

constexpr explicit operator bool() const noexcept;
  • 返回值

    has_value().

已检查值访问
constexpr U& value(
  boost::source_location const & loc = BOOST_CURRENT_LOCATION ) const;
  • 效果

    如果 *this 包含引用,则返回它。否则,调用 throw_exception_from_error,并向其传递对所包含错误的引用和 loc

未检查值访问
constexpr U* operator->() const noexcept;
  • 返回值

    如果 *this 包含引用,则返回指向其引用对象的指针。否则,返回 nullptr

constexpr U& operator*() const noexcept;
  • 要求

    *this 包含一个引用。

    返回值

    *operator->().

错误访问
constexpr E error() const &;
constexpr E error() &&;
  • 效果

    如果 *this 包含错误,则返回它。否则,返回 E()

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

    *this 持有引用 static_cast<U&>( std::forward<A>(a)…​ ).

    返回值

    所包含的引用。

    备注

    仅当 AB&std::is_convertible<B*, U*>::valuetrue 时,此函数才启用。

swap
constexpr void swap( result& r );
  • 效果

    交换 *thisr 的内容。

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

    交换 r1r2 的内容。

相等性
friend constexpr bool operator==( result const & r1, result const & r2 );
  • 效果
    • 如果 r1 包含引用 t1r2 包含引用 t2,则返回 t1 == t2

    • 如果 r1 包含错误 e1r2 包含错误 e2,则返回 e1 == e2

    • 否则,返回 false

friend constexpr bool operator!=( result const & r1, result const & r2 );
  • 返回值

    !( r1 == r2 ).

链式调用

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 );
  • 返回 r 中的值,如果 r 包含错误,则返回默认值 u

    效果
    • 如果 r.has_value()true,则返回 *r

    • 否则,返回 u

    备注

    仅当 U 可转换为 T 时启用。

    示例
    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 );
  • 返回 r 中的值,如果 r 包含错误,则返回通过调用函数 f 获得的默认值。

    效果
    • 如果 r.has_value()true,则返回 *r

    • 否则,返回 f()

    备注

    仅当 f() 可转换为 T 时启用。

    示例
    result<int> get_server_port(); // can fail
    int get_default_port();
    
    int get_port()
    {
        return get_server_port() | get_default_port;
    }

    请注意,右侧是 get_default_port 而不是 get_default_port()。这很重要;这样拼写,仅当 get_server_port_impl() 失败时才调用函数 get_default_port。如果是

        return get_server_port() | get_default_port();

    该函数将无条件地被调用。

    另一种等效的方法是使用 lambda 表达式

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

    这里不需要,但对于更复杂的表达式是必需的。

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 );
  • 返回 r 中的值,如果 r 包含错误,则返回通过调用函数 f 获得的另一个 result

    Rf() 的类型。

    效果
    • 如果 r.has_value()true,则返回 *r

    • 否则,返回 f()

    备注

    仅当 Rresult 的实例且 T 可转换为 R::value_type 时启用。

    示例
    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 );
  • 如果 r 包含错误,则为其分配一个由 u 构造的值。

    效果

    如果 r.has_value()false,则将 u 分配给 r

    返回值

    r.

    备注

    仅当 U 可转换为 T 时启用。

template<class T, class E, class F> result<T, E>& operator|=( result<T, E>& r, F&& f );
  • 如果 r 包含错误,则为其分配 f()

    效果

    如果 r.has_value()false,则将 f() 分配给 r

    返回值

    r.

    备注

    仅当 f() 的类型为以下两种情况之一时启用

    • 可转换为 T

    • result 的实例,可转换为 result<T, E>

    示例
    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 );
  • 返回 r 中的错误,如果 r 包含值,则通过对其调用 f 来转换该值。

    Uf(*r) 的类型。

    效果
    • 如果 r.has_value()true,则返回 f(*r)

    • 否则,返回 r.error()

    备注

    仅当 U 不是 result 的实例时启用。

    示例
    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 );
  • 返回 r 中的错误,如果 r 包含值,则将其替换为调用 f 的结果。

    Uf() 的类型。

    效果
    • 如果 r.has_value()true,则返回 f()

    • 否则,返回 r.error()

    备注

    仅当 U 不是 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 );
  • 返回 r 中的错误,如果 r 包含值,则返回通过对 r 中的值调用函数 f 获得的另一个 result

    Rf(*r) 的类型。

    效果
    • 如果 r.has_value()true,则返回 f(*r)

    • 否则,返回 r.error()

    备注

    仅当 Rresult 的实例且 E 可转换为 R::error_type 时启用。

    示例
    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 );
  • 返回 r 中的错误,如果 r 包含值,则返回通过调用函数 f 获得的另一个 result

    Rf() 的类型。

    效果
    • 如果 r.has_value()true,则返回 f()

    • 否则,返回 r.error()

    备注

    仅当 Rresult 的实例且 E 可转换为 R::error_type 时启用。

operator&=
template<class T, class E, class F, class U = ...>
  result<T, E>& operator&=( result<T, E>& r, F&& f );
  • 如果 r 包含值,则将其替换为对 r 中的值调用函数 f 的结果。

    Uf(*r) 的类型。

    效果

    如果 `r.has_value() 为 `true`,则将 `f(*std::move(r))` 分配给 `r`。

    返回值

    r.

    备注

    仅当 U 不是 result 的实例且可转换为 T 时启用。

template<class T, class E, class F, class R = ...>
  result<T, E>& operator&=( result<T, E>& r, F&& f );
  • 如果 r 包含值,则将其替换为对 r 中的值调用函数 f 的结果。

    Rf(*r) 的类型。

    效果

    如果 `r.has_value() 为 `true`,则将 `f(*std::move(r))` 分配给 `r`。

    返回值

    r.

    备注

    仅当 Rresult 的实例且可转换为 result<T, E> 时启用。

    示例
    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 );
  • 如果 r 包含值,则将其替换为调用函数 f 的结果。

    Rf() 的类型。

    效果

    如果 r.has_value()true,则将 f() 分配给 r

    返回值

    r.

    备注

    仅当 Rresult<void, E2> 的实例并且 E2 可转换为 E 时启用。

<boost/system.hpp>

此便捷的头文件包含前面描述的所有头文件。

历史

N1975,TR2 的文件系统库提案,在柏林会议上被技术报告 2 (TR2) 接受,其中包含用于补充标准库诊断条款的附加组件。从那时起,这些错误报告组件受到了更广泛的公众审查,并且对其设计进行了增强。增强版本已被 N2054(TR2 的网络库提案)使用,这表明这些错误报告组件在最初的文件系统库之外也很有用。

最初的提案将错误类别视为 errno(即 POSIX 样式)和本机操作系统的错误代码之间的二元选择。建议的组件现在允许实现或用户需要的尽可能多的其他错误类别。例如,在某些网络库实现中需要支持其他错误类别,因为它们构建在 POSIX getaddrinfo API 之上,该 API 使用不基于 errno 的错误代码。

致谢

Christopher Kohlhoff 和 Peter Dimov 对设计做出了重要贡献。还收到了 Pavel Vozenilek、Gennaro Prota、Dave Abrahams、Jeff Garland、Iain Hanson、Oliver Kowalke 和 Oleg Abrosimov 的意见和建议。Christopher Kohlhoff 对 N2066 论文提出了一些改进建议。Johan Nilsson 的评论促成了 N2066 中的几项改进。

这份文档是

  • Copyright 2003-2017 Beman Dawes

  • Copyright 2018-2022 Peter Dimov

并根据 Boost 软件许可证 1.0 版 分发。