简介
源自操作系统或其他底层应用程序接口 (API) 的错误通常通过整数表示的错误代码来报告,可以通过直接从函数返回代码(例如 pthread_mutex_init
),或者使用边信道,例如 POSIX 下的 errno
伪变量或 Windows 下的 GetLastError()
。
但是,只有当已知这些整数错误值的来源时,才能对其进行解释。在 Windows 下,当 GetLastError()
返回值 5 时,表示 ERROR_ACCESS_DENIED
,但当从 errno
检索时,表示 EIO
。相反,相同的错误条件“拒绝访问”在 GetLastError()
返回时用值 5 表示,在从 errno
检索时用 13 (EACCES
) 表示。
这意味着,为了使代码能够处理来自这两个来源的错误(检索描述错误的文本消息,或检查错误是否表示“拒绝访问”),它需要知道整数错误值的来源。为了实现这一点,整数错误值需要附带一条标识来源的信息。
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
,也可以从 std::error_code
构造。
用法
以下所有代码片段都假定这些行
#include <boost/system.hpp>
namespace sys = boost::system;
生效。
从 POSIX 下的操作系统 API 返回错误
假设我们正在实现一个可移植的 file
包装器,用于操作系统文件 API。其一般轮廓如下所示
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
中的错误值标记为属于通用类别。
也可以使用系统类别,因为 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()
,加上构造时提供的 prefix 前缀,也是 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
重载现在很简单
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
条件。例如,在 POSIX 函数会返回 EINVAL
的情况下,返回 Z_STREAM_ERROR
;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
中的其他类型的失败 - 这些失败将来自 file::read
,load_image_header
将使用它来读取标头。)
为了定义这些错误,我们将使用作用域枚举类型。(此示例将利用 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_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()
现在已被弃用,不鼓励使用。 -
接受单个
error_code
参数的system_error
的构造函数现在是显式的。 -
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
的类型为 error_code
)中误导性的转换为 bool
的情况。它本身也很有用。
参考
宏
当定义了 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
的重载。这允许创建通用错误代码,这是一种通常在函数需要发出不来自底层 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
当结果持有错误时,result<T, E>::value()
会调用函数 throw_exception_from_error
。其目的是抛出一个表示结果中持有的错误的异常。
已经为 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
不为 null,则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<T, E>
的result
的实例。
-
- 示例
-
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
包含值,则返回通过在其上调用函数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
的结果。令
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
包含值,则将其替换为调用函数f
在r
中的值上调用的结果。令
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
中的值上调用的结果。令
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
包含值,则将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
,因此需要支持其他错误类别。
致谢
克里斯托弗·科尔霍夫和彼得·迪莫夫为设计做出了重要贡献。 Pavel Vozenilek、Gennaro Prota、Dave Abrahams、Jeff Garland、Iain Hanson、Oliver Kowalke 和 Oleg Abrosimov 也提出了意见和建议。 克里斯托弗·科尔霍夫对 N2066 论文提出了多项改进建议。 Johan Nilsson 的评论促成了 N2066 中的多项改进。