簡介
來自作業系統或其他低階應用程式介面 (API) 的錯誤,通常會透過一個表示錯誤碼的整數來回報,無論是直接從函式回傳錯誤碼(例如 pthread_mutex_init
),還是透過邊通道(side channel),例如 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 下從 OS API 回傳錯誤
假設我們正在實作一個可移植的 file
包裝器,以封裝 OS 檔案 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
函式會回傳傳輸的位元組數,並透過類型為 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
值來自作業系統(「系統」),我們會為其使用系統類別。那是因為系統類別值可能是泛型(平台獨立)值的平台特定超集。
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 const
而不是 static constexpr
。另一個選項是 BOOST_STATIC_CONSTEXPR
,這是一個 Boost.Config 巨集,會根據情況擴充為 static constexpr
或 static const
。
為了避免每次都重複使用 ec.assign
這個樣板程式碼,我們可以定義一個巨集
#define ASSIGN(ec, ...) { \
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; \
(ec).assign(__VA_ARGS__, &loc); }
現在我們可以用它來擴充,例如,file::write
的 POSIX 實作
std::size_t file::write( void const * buffer, std::size_t size, sys::error_code& ec )
{
if( size > SSIZE_MAX )
{
ASSIGN( ec, EINVAL, sys::generic_category() );
return 0;
}
ssize_t r = ::write( fd_, buffer, size );
if( r < 0 )
{
ASSIGN( ec, errno, sys::system_category() );
return 0;
}
if( r < size )
{
ASSIGN( ec, ENOSPC, sys::generic_category() );
}
else
{
ec = {}; // ec.clear(); under C++03
}
return r;
}
取得錯誤碼的文字表示,以進行記錄和顯示
假設我們有一個由某個函式返回的 error_code
實例 ec
,我們有多種方法可以取得其中表示的錯誤碼的文字表示。
ec.to_string()
會提供將 ec
串流到 std::ostream
的結果,例如,如果 std::cout << ec << std::endl;
輸出 system:6
,這就是 ec.to_string()
會返回的結果。(在 Windows 下,system:6
是來自 <winerror.h>
的 ERROR_INVALID_HANDLE
。)
若要取得對應於此程式碼的人類可讀錯誤訊息,我們可以使用 ec.message()
。對於 ERROR_INVALID_HANDLE
,它會給我們「控制代碼無效」的訊息 — 可能是本地化的。
如果 ec
包含來源位置,我們可以透過 ec.location().to_string()
取得其文字表示。這會給我們類似於以下的內容
C:\Projects\testbed2019\testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)'
如果 ec
中有位置,則會顯示以上內容,以及
(unknown source location)
如果沒有位置則會顯示以上內容。(當 ec
包含位置時,ec.has_location()
為 true
。)
最後,ec.what()
會給我們一個包含以上所有內容的字串,類似如下
The handle is invalid [system:6 at C:\Projects\testbed2019\testbed2019.cpp:98 in function 'unsigned __int64 __cdecl file::read(void *,unsigned __int64,class boost::system::error_code &)']
大多數不打算給終端使用者看的日誌記錄和診斷輸出,可能最終都會使用 what()
。(ec.what()
,加上建構時提供的字首,也是 boost::system::system_error::what()
會返回的內容。)
組合回傳錯誤碼的函式
假設我們需要實作一個檔案複製函式,其介面如下
std::size_t file_copy( file& src, file& dest, sys::error_code& ec );
file_copy
使用 src.read
從 src
讀取位元組,然後使用 dest.write
將這些位元組寫入 dest
。此過程會持續到其中一個操作發出錯誤訊號,或直到到達檔案結尾。它會傳回寫入的位元組數,並使用 ec
來發出錯誤訊號。
以下是一個可能的實作
std::size_t file_copy( file& src, file& dest, sys::error_code& ec )
{
std::size_t r = 0;
for( ;; )
{
unsigned char buffer[ 1024 ];
std::size_t n = src.read( buffer, sizeof( buffer ), ec );
// read failed, leave the error in ec and return
if( ec.failed() ) return r;
// end of file has been reached, exit loop
if( n == 0 ) return r;
r += dest.write( buffer, n, ec );
// write failed, leave the error in ec and return
if( ec.failed() ) return r;
}
}
請注意,POSIX 和 Windows 實作之間不再有任何差異;它們的差異包含在 file::read
和 file::write
中。file_copy
是可移植的,可在任何平台上運作。
在撰寫此類較高階函式時,一般模式是將它們從呼叫者接收到的輸出 error_code
參數 ec
直接作為輸出參數傳遞給它們所基於的較低階函式。這樣一來,當它們偵測到中間操作發生錯誤時(透過測試 ec.failed()
),它們可以立即返回給呼叫者,因為錯誤碼已經在正確的位置。
請注意,file_copy
甚至不需要透過使用 ec = {};
在成功時清除 ec
。由於我們已經測試過 ec.failed()
,我們知道 ec
包含一個表示成功的值。
提供雙重(拋出和不拋出)多載函式
透過輸出 error_code& ec
參數發出錯誤訊號的函式,要求呼叫者在呼叫它們後檢查 ec
,並採取適當的動作(例如立即返回,如上所述)。忘記檢查 ec
會導致邏輯錯誤。
雖然這對某些人來說是偏好的程式碼風格,但其他人則偏好例外,這樣就不會忘記檢查。
Boost.Filesystem(後來變成 std::filesystem
)引入了一種方法,即提供兩種替代方案:一個不拋出例外且接受 error_code& ec
的函式,如上面的 file_copy
,以及一個不接受 error_code
輸出參數,並在失敗時拋出例外的函式。
這是如何實作第二個拋出例外的函式的典型方式
std::size_t file_copy( file& src, file& dest )
{
sys::error_code ec;
std::size_t r = file_copy( src, dest, ec );
if( ec.failed() ) throw sys::system_error( ec, __func__ );
return r;
}
也就是說,我們只需呼叫 file_copy
的不拋出例外多載,如果它在 ec
中發出失敗訊號,則拋出 system_error
例外。
我們使用我們的函式名稱 __func__
("file_copy"
) 作為字首,儘管這只是個人喜好。
請注意,通常在此樣式下,接受 error_code& ec
的多載會使用 noexcept
裝飾,以便清楚地表明它們不會拋出例外(儘管為了保持程式碼與 C++03 相容,我們在前面的範例中沒有這樣做。)
result<T> 作為雙重 API 的替代方案
除了為每個操作提供兩個函式之外,另一種方法是讓函式傳回 sys::result<T>
而不是 T
。result<T>
是一個類別,其中包含 T
或 error_code
,類似於 variant<T, error_code>
。
偏好檢查錯誤而不依賴例外的客戶端,可以透過 if( r )
或其更詳細的等效表示 if( r.has_value() )
來測試 result<T> r
是否包含值,然後透過 *r
或 r.value()
取得該值。如果 r
不包含值,則可以使用 r.error()
取得其包含的 error_code
。
偏好例外的使用者只需直接呼叫 r.value()
,無需檢查。在沒有值的情況下,這會自動拋出一個對應於 r
中 error_code
的 system_error
例外。
假設我們的基本 file
API 沒有變更,則 file_copy
的這種變體看起來會像這樣
sys::result<std::size_t> file_copy( file& src, file& dest )
{
std::size_t r = 0;
sys::error_code ec;
for( ;; )
{
unsigned char buffer[ 1024 ];
std::size_t n = src.read( buffer, sizeof( buffer ), ec );
if( ec.failed() ) return ec;
if( n == 0 ) return r;
r += dest.write( buffer, n, ec );
if( ec.failed() ) return ec;
}
}
這裡唯一的區別是我們在錯誤時傳回 ec
,而不是 r
。
但是請注意,我們不再能夠同時傳回錯誤碼和傳輸的位元組數;也就是說,我們不再能夠發出*部分成功*的訊號。這在較高階別通常不是問題,但諸如 file::read
和 file::write
等較低階的基本類型最好使用舊的樣式來撰寫。
儘管如此,為了示範如何組合傳回 result
的 API,我們將展示如果 file::read
和 file::write
傳回 result<size_t>
時,file_copy
的樣子
class file
{
public:
// ...
sys::result<std::size_t> read( void * buffer, std::size_t size );
sys::result<std::size_t> write( void const * buffer, std::size_t size );
};
sys::result<std::size_t> file_copy( file& src, file& dest )
{
std::size_t m = 0;
for( ;; )
{
unsigned char buffer[ 1024 ];
auto r = src.read( buffer, sizeof( buffer ) );
if( !r ) return r;
std::size_t n = *r;
if( n == 0 ) return m;
auto r2 = dest.write( buffer, n );
if( !r2 ) return r2;
std::size_t n2 = *r2;
m += n2;
}
}
測試特定錯誤條件
假設我們已經呼叫了一個使用 error_code
發出失敗訊號的函式,我們已將 error_code
變數 ec
傳遞給它,現在由於某些原因,我們想檢查該函式是否因 EINVAL
(「無效引數」)的錯誤碼而失敗。
由於 error_code
可以比較是否相等,因此我們的第一個直覺可能是 if( ec == error_code( EINVAL, generic_category() )
。
這是錯誤的,我們絕不應該這樣做。
首先,在 POSIX 下,該函式可能會從系統類別傳回 EINVAL
(因為錯誤可能由作業系統 API 返回,而不是由函式本身返回,就像我們的 read
和 write
實作中的情況一樣。)
由於 error_code
比較是精確的,因此來自通用類別的 EINVAL
與來自系統類別的 EINVAL
不會比較為相等。
(在您開始考慮將 ec.value()
與 EINVAL
進行比較之前,請繼續閱讀。)
其次,在 Windows 下,該函式可能會傳回 error_code( ERROR_INVALID_PARAMETER, system_category() )
。正如我們已經提到的,Windows 下系統類別中的整數錯誤值與整數 errno
值完全無關。
正確的方法是將 ec
與 error_condition( EINVAL, generic_category() )
比較,而不是與特定的錯誤碼比較。錯誤條件是一種與平台無關的方式來表示具體錯誤碼的含義。在我們的案例中,在 POSIX 和 Windows 下,所有表示 EINVAL
的錯誤碼都將與 error_condition( EINVAL, generic_category() )
比較為相等。
簡而言之,您絕不應該將錯誤碼與錯誤碼進行比較,而應該將它們與錯誤條件進行比較。這就是 error_condition
類別的目的,而這個類別經常被誤解。
由於
if( ec == sys::error_condition( EINVAL, sys::generic_category() ) )
{
// handle EINVAL
}
有點冗長,因此 Boost.System 為 errno
值提供了列舉值,可以直接將錯誤碼與之比較。
這些列舉值定義在 <boost/system/errc.hpp>
中,並使上述測試可以寫成
if( ec == sys::errc::invalid_argument )
{
// handle EINVAL
}
這是我們通常應該用來測試特定錯誤條件的最佳做法。
調整現有的整數錯誤值
具有 C (或 extern "C"
) API 的程式庫通常會透過傳回程式庫特定的整數錯誤碼來發出失敗訊號(通常保留零表示「無錯誤」。)在撰寫可移植的 C++ 包裝函式時,我們需要決定如何公開這些錯誤碼,而使用 error_code
是一種很好的方式。
由於整數錯誤碼是程式庫特定的,且通常與 errno
值或系統類別值不符,因此我們需要定義一個程式庫特定的錯誤類別。
調整 SQLite 錯誤
我們將以 SQLite 為例。自訂錯誤類別的一般概述如下
class sqlite3_category_impl: public sys::error_category
{
// TODO add whatever's needed here
};
sys::error_category const& sqlite3_category()
{
static const sqlite3_category_impl instance;
return instance;
}
然後可以像使用預定義的通用和系統類別一樣使用它
int r = some_sqlite3_function( ... );
ec.assign( r, sqlite3_category() );
如果我們嘗試按原樣編譯上述類別定義,它會抱怨我們沒有實作兩個純虛擬成員函式 name
和 message
,因此至少我們需要新增這些函式。此外,我們還將實作 message
的非配置多載。它不是純虛擬函式,但其預設實作會呼叫傳回 std::string
的多載,而這幾乎不是我們想要的。(提供此預設實作只是為了向後相容性,以便不會破壞在此多載新增之前撰寫的現有使用者定義類別。)
因此,我們需要實作的最小值是這樣
class sqlite3_category_impl: public sys::error_category
{
public:
const char * name() const noexcept;
std::string message( int ev ) const;
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
};
name
很簡單,它只傳回類別名稱
const char * sqlite3_category_impl::name() const noexcept
{
return "sqlite3";
}
message
用於取得給定整數錯誤碼的錯誤訊息。SQLite 為此提供了函式 sqlite3_errstr
,因此我們不需要做任何工作
std::string sqlite3_category_impl::message( int ev ) const
{
return sqlite3_errstr( ev );
}
char const * sqlite3_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
{
std::snprintf( buffer, len, "%s", sqlite3_errstr( ev ) );
return buffer;
}
我們完成了。sqlite3_category()
現在可以像使用預定義類別一樣使用,並且我們可以透過 ec.assign( r, sqlite3_category() )
將 SQLite 錯誤碼 int r
放入 Boost.System error_code ec
中。
調整 ZLib 錯誤
另一個廣泛使用的 C 程式庫是 ZLib,下面顯示了 zlib.h
中定義其錯誤碼的部分
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_NEED_DICT 2
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
#define Z_VERSION_ERROR (-6)
/* Return codes for the compression/decompression functions. Negative values
* are errors, positive values are used for special but normal events.
*/
與先前的 SQLite 案例相比,有三個相關的差異
-
雖然對於 SQLite,所有非零值都是錯誤,這是典型的情況,但這裡的負值是錯誤,而正值是「特殊但正常」的值,也就是說,它們表示成功,而不是失敗;
-
ZLib 沒有提供傳回對應於特定錯誤碼的錯誤訊息的函式;
-
當傳回
Z_ERRNO
時,應從errno
擷取錯誤碼。
我們的類別實作如下
class zlib_category_impl: public sys::error_category
{
public:
const char * name() const noexcept;
std::string message( int ev ) const;
char const * message( int ev, char * buffer, std::size_t len ) const noexcept;
bool failed( int ev ) const noexcept;
};
sys::error_category const& zlib_category()
{
static const zlib_category_impl instance;
return instance;
}
與往常一樣,name
的實作很簡單
const char * zlib_category_impl::name() const noexcept
{
return "zlib";
}
這次我們需要更努力地實作 message
,因為沒有預先存在的函式可以依靠
char const * zlib_category_impl::message( int ev, char * buffer, std::size_t len ) const noexcept
{
switch( ev )
{
case Z_OK: return "No error";
case Z_STREAM_END: return "End of stream";
case Z_NEED_DICT: return "A dictionary is needed";
case Z_ERRNO: return "OS API error";
case Z_STREAM_ERROR: return "Inconsistent stream state or invalid argument";
case Z_DATA_ERROR: return "Data error";
case Z_MEM_ERROR: return "Out of memory";
case Z_BUF_ERROR: return "Insufficient buffer space";
case Z_VERSION_ERROR: return "Library version mismatch";
}
std::snprintf( buffer, len, "Unknown zlib error %d", ev );
return buffer;
}
這是非拋出 message
多載的典型實作。請注意,允許 message
傳回與 buffer
不同的內容,這表示我們可以直接傳回字元常值,而無需先將它們複製到提供的緩衝區中。這讓我們的函式即使在緩衝區太小時也能傳回正確的訊息文字。
message
的 std::string
多載現在很簡單
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() );
}
}
因此,程式碼將執行
int r = some_zlib_function( ... );
assign_zlib_error( ec, r );
而不是直接使用 ec.assign( r, zlib_category() )
。
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 );
}
}
我們可以就此停止,因為這涵蓋了我們打算做的一切,但是我們可以採取額外的步驟,為我們的錯誤碼啟用來源位置。為此,我們需要將 assign_zlib_error
變更為接受 source_location
#define ASSIGN_ZLIB_ERROR(ec, r) { \
BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; \
assign_zlib_error( ec, r, &loc ); }
定義一個輔助巨集,以避免每次都定義 static constexpr
來源位置物件的樣板程式碼
int r = some_zlib_function( ... );
ASSIGN_ZLIB_ERROR( ec, r );
支援與條件進行比較
然後使用巨集代替函式
為了編碼這種關係,我們需要在我們的類別中實作 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
現在會透過預設引數自動將BOOST_CURRENT_LOCATION
提供給throw_exception_from_error
。 -
新增了一個接受來源位置的
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 現在是僅標頭程式庫。為了相容性,仍然會建立一個 Stub 程式庫,但不再需要連結它。
-
更多函數已標記為
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 介面,並在使用 Boost.System 時,直接或透過 Boost.ASIO 等相依性,透過 std::error_code
報告錯誤。
設計原理
error_code
和 error_condition
被設計為值類型,因此它們可以被複製而不會發生切割 (slicing),也不需要堆積 (heap) 配置,但仍然可以根據錯誤類別擁有多型行為。這是透過抽象基底類別 error_category
提供多型行為來實現的,而 error_code
和 error_condition
則包含一個指向衍生自 error_category
的類型物件的指標。
許多詳細的設計決策都是受到以下要求的驅使:使用者能夠添加額外的錯誤類別,並且撰寫可移植程式碼不會比撰寫特定系統程式碼更困難。
針對 error_code
的 operator<<
多載消除了像 cout << ec
這樣程式碼中誤導性的轉換為 bool
的情況,其中 ec
的類型為 error_code
。它本身也很有用。
參考資料
巨集
當定義了 BOOST_SYSTEM_ENABLE_DEPRECATED
時,函式庫會提供已棄用的功能以保持相容性。這些功能最終將會消失。
當定義了 BOOST_SYSTEM_USE_UTF8
時,在 Windows 上,函式庫會使用程式碼頁 CP_UTF8
返回 UTF-8 訊息,而不是預設的 CP_ACP
。這個巨集在 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
包含值,則傳回透過對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
取代為對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
包含值,則將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 樣式)和原生作業系統錯誤碼之間的二元選擇。現在提出的組件允許實作或使用者需要盡可能多的額外錯誤類別。例如,在某些網路函式庫實作中,需要支援額外的錯誤類別,因為它們是建立在基於非 errno
的錯誤碼的 POSIX getaddrinfo
API 之上的。
致謝
Christopher Kohlhoff 和 Peter Dimov 對設計做出了重要的貢獻。Pavel Vozenilek、Gennaro Prota、Dave Abrahams、Jeff Garland、Iain Hanson、Oliver Kowalke 和 Oleg Abrosimov 也提供了評論和建議。Christopher Kohlhoff 對 N2066 文件提出了多項改進建議。Johan Nilsson 的評論導致了 N2066 中的多項改進。