引言
源自操作系统或其他低级应用程序接口 (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 constexpr
或 static 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.read
从 src
读取字节,然后使用 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::read
和 file::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>
而不是 T
。result<T>
是一个持有 T
或 error_code
的类,类似于 variant<T, error_code>
。
喜欢检查错误而不依赖异常的客户端可以通过 if( r )
或其更详细的等效项 if( r.has_value() )
来测试 result<T> r
是否包含值,然后通过 *r
或 r.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::read
和 file::write
)最好使用旧样式编写。
不过,为了演示如何组合返回 result
的 API,我们将展示如果 file::read
和 file::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 返回,而不是由函数本身返回,如我们的 read
和 write
实现中的情况)。
由于 error_code
比较是精确的,因此来自泛型类别的 EINVAL
与来自系统类别的 EINVAL
不相等。
(在你开始考虑仅将 ec.value()
与 EINVAL
进行比较之前,请继续阅读。)
其次,在 Windows 下,该函数可能已返回 error_code( ERROR_INVALID_PARAMETER, system_category() )
。正如我们已经提到的,Windows 下系统类别中的整数错误值与整数 errno
值完全无关。
正确的方法是将 ec
与 error_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() );
如果我们尝试按原样编译上述类别定义,它将抱怨我们没有实现两个纯虚成员函数 name
和 message
,因此我们至少需要添加这些函数。此外,我们还将实现 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_code
和 error_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_category
、error_code
和 error_condition
到它们在 <system_error>
中的标准等效物的隐式转换。
这允许库公开 C++11 接口并通过 std::error_code
报告错误,即使使用 Boost.System(直接或通过依赖项(例如 Boost.ASIO))。
设计原理
error_code
和 error_condition
被设计为值类型,因此它们可以在不发生切割的情况下进行复制,并且不需要堆分配,但仍然具有基于错误类别的多态行为。这是通过抽象基类 error_category
提供多态行为,以及 error_code
和 error_condition
包含指向从 error_category
派生的类型的对象的指针来实现的。
许多详细的设计决策都是由用户能够添加其他错误类别以及编写可移植代码不比编写系统特定代码更难的要求驱动的。
error_code
的 operator<<
重载消除了在诸如 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
时将提供它们。
旧用法,现已弃用 | 替换 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<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 )
,然后返回对它的引用。 - 备注
-
仅当
T
为std::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>::value
为true
时,此构造函数才启用。
修饰符
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>::value
为true
时,此运算符才启用。
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;
-
- 返回值
-
根据构造函数,返回
ec
或error_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_error
由 result<T, E>::value()
调用。其目的是抛出一个表示结果中包含的错误的异常。
已经为 E
为 error_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>::value
为true
时,此构造函数才启用。
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…>::value
为true
时,此构造函数才启用。
template<class... A>
constexpr result( in_place_error_t, A&&... a );
-
- 确保
-
*this
包含错误E( std::forward<A>(a)… )
。 - 备注
-
仅当
std::is_constructible<E, A…>::value
为true
时,此构造函数才启用。
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>::value
为true
时,此构造函数才启用。
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>::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 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 );
-
- 效果
-
交换
*this
和r
的内容。
friend constexpr void swap( result & r1, result & r2 );
-
- 效果
-
交换
r1
和r2
的内容。
相等性
friend constexpr bool operator==( result const & r1, result const & r2 );
-
- 效果
-
-
如果
r1
包含值t1
且r2
包含值t2
,则返回t1 == t2
。 -
如果
r1
包含错误e1
且r2
包含错误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…>::value
为true
时,此构造函数才启用。
template<class E2>
constexpr result( result<void, E2> const& r2 );
-
- 确保
-
如果
r2.has_value()
为true
,则*this
包含一个未指定的值,否则*this
包含错误E( r2.error() )
。 - 备注
-
仅当
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 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 );
-
- 效果
-
交换
*this
和r
的内容。
friend constexpr void swap( result & r1, result & r2 );
-
- 效果
-
交换
r1
和r2
的内容。
相等性
friend constexpr bool operator==( result const & r1, result const & r2 );
-
- 效果
-
-
如果
r1
和r2
包含值,则返回true
。 -
如果
r1
包含错误e1
且r2
包含错误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) )
。 - 备注
-
仅当
A
为B&
且std::is_convertible<B*, U*>::value
为true
时,此构造函数才启用。
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) )
。 - 备注
-
仅当
A
为B&
且std::is_convertible<B*, U*>::value
为true
时,此构造函数才启用。
template<class... A>
constexpr result( in_place_error_t, A&&... a );
-
- 确保
-
*this
包含错误E( std::forward<A>(a)… )
。 - 备注
-
仅当
std::is_constructible<E, A…>::value
为true
时,此构造函数才启用。
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)… )
. - 返回值
-
所包含的引用。
- 备注
-
仅当
A
为B&
且std::is_convertible<B*, U*>::value
为true
时,此函数才启用。
swap
constexpr void swap( result& r );
-
- 效果
-
交换
*this
和r
的内容。
friend constexpr void swap( result & r1, result & r2 );
-
- 效果
-
交换
r1
和r2
的内容。
相等性
friend constexpr bool operator==( result const & r1, result const & r2 );
-
- 效果
-
-
如果
r1
包含引用t1
且r2
包含引用t2
,则返回t1 == t2
。 -
如果
r1
包含错误e1
且r2
包含错误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
。设
R
为f()
的类型。- 效果
-
-
如果
r.has_value()
为true
,则返回*r
。 -
否则,返回
f()
。
-
- 备注
-
仅当
R
是result
的实例且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
来转换该值。设
U
为f(*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
的结果。设
U
为f()
的类型。- 效果
-
-
如果
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
。设
R
为f(*r)
的类型。- 效果
-
-
如果
r.has_value()
为true
,则返回f(*r)
。 -
否则,返回
r.error()
。
-
- 备注
-
仅当
R
是result
的实例且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
。设
R
为f()
的类型。- 效果
-
-
如果
r.has_value()
为true
,则返回f()
。 -
否则,返回
r.error()
。
-
- 备注
-
仅当
R
是result
的实例且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
的结果。设
U
为f(*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
的结果。设
R
为f(*r)
的类型。- 效果
-
如果 `r.has_value() 为 `true`,则将 `f(*std::move(r))` 分配给 `r`。
- 返回值
-
r
. - 备注
-
仅当
R
是result
的实例且可转换为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
的结果。设
R
为f()
的类型。- 效果
-
如果
r.has_value()
为true
,则将f()
分配给r
。 - 返回值
-
r
. - 备注
-
仅当
R
是result<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 中的几项改进。