介绍
来自操作系统或其他低级应用程序编程接口 (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 下,系统类别表示 OS API 返回的 errno
值(通用类别的超集),而在 Windows 下,系统类别表示 GetLastError()
返回的错误值。
该框架是可扩展的。用户可以通过派生自 error_category
的类并实现一个返回其实例引用的函数来定义自己的类别。此功能对于描述库定义的错误值以及调整返回整数错误值的现有 C API 库都非常有用。
对于那些喜欢通过异常报告错误的用户,Boost.System 提供了一个存储 error_code
的标准异常类 system_error
。
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 下从 OS API 返回错误
假设我们正在实现一个围绕 OS 文件 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
函数返回传输的字节数,并通过类型为 boost::system::error_code
的输出参数 ec
信号错误。
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
值来自 OS(“系统”),我们使用系统类别来表示它。这是因为系统类别值可能是通用(平台独立)值的平台特定超集。
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 下从 OS 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
实现存在一个问题;它接受 size
的 std::size_t
值,但是当请求值不适合 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 constexpr
,需要使用 static const
。另一个选项是 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
(因为错误可能由 OS 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() )
进行比较。错误条件是一种独立于平台的方式,用于表示具体错误码的含义。在我们的例子中,所有表示 EINVAL
的错误码,无论是在 POSIX 还是 Windows 下,都将与 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
条件。例如,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
中返回其他类型的故障——这些故障将来自 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++ 上)。 -
将
value_type
、error_type
、in_place_value
、in_place_error
添加到result<>
。 -
将
emplace
添加到result<>
。
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
,而不是来自系统类别。这在 POSIX 中发生,当输入error_code
来自系统类别且不对应任何errc_t
值时。 -
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
不为空,则为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)… )
。 - 返回
-
对包含值的引用。
交换
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
存储一个未指定的值。
交换
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
时启用。
交换
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_default_port
仅在get_server_port_impl()
失败时被调用。如果是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
包含一个值,则返回通过对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 中的多项改进。
版权和许可
本文档
-
版权所有 2003-2017 Beman Dawes
-
版权所有 2018-2022 Peter Dimov