使用 C++20 的單標頭 std::expected 實作。
圖書館實施了這兩項提案:
此實作在命名空間 rd 中提供了預期的功能。因此,對於 std::expected 的任何使用,請使用 rd::expected。
std::expected 是一種錯誤處理機制。這與 Rust 的 std::result 非常相似。 std::expected 基本上包含結果或錯誤之一。
不「總是」使用異常可能有兩個原因:
在編寫任何程式庫時,這都會為錯誤處理帶來大問題。在庫中,如果我們選擇在錯誤情況下拋出異常,那麼我們就是在為庫用戶做出選擇。在使用該程式庫的應用程式上下文中,庫中的錯誤情況可能是也可能不是異常情況。
std::expected 提供了異常的標準替代方案,可用於在應用程式上下文中不異常的錯誤條件。
在這麼說的同時,應該注意的是,異常對於恐慌情況非常有用。並且存在許多明顯的恐慌情況,對於這些情況只能使用例外。
error_code 曾經是最簡單的錯誤處理機制。從歷史上看,error_code 是一個簡單的整數,這不利於豐富的錯誤上下文。
如今,C++頭檔<system_error>提供了更豐富的錯誤程式碼。然而,error_code會導致返回通道的壟斷。因此需要通過其他通道輸出值。
它還強制您在每次函數呼叫後編寫 if 條件。
std::expected 保證它永遠不會為空。即,它在任何時間點都將包含值或錯誤之一。這使得它非常易於使用。
auto get_file_handle (std::string_view path) -> rd::expected<file, fail_reason>;
auto read_file (file f) -> rd::expected<std::string, fail_reason>;
auto to_int (std::string str) -> rd::expected<int, fail_reason>;
auto increment ( int x) -> int;
auto read_int_with_increment (std::string_view path) -> rd::expected<int, fail_reason>{
return get_file_handle (path)
. and_then (read_file)
. and_then (to_int)
. transform (increment);
}
template < typename T, typename E>
class expected
T、E 不能是引用型,因為它們在論文中也不支持。
using value_type = T;
using error_type = E;
using unexpected_type = unexpected<E>;
template < class U >
using rebind = expected<U, error_type>;
預設構造函數:
constexpr expected ();
複製建構函式:
constexpr expected (expected const &);
移動構造函數:
constexpr expected (expected &&);
預期的建構子:
U 應可轉換為 T,G 應可轉換為 E。
template < class U , class G >
constexpr expected (expected<U, G> const &);
template < class U , class G >
constexpr expected (expected<U, G> &&);
值建構函數:
預期 <T , E> 的建構函數,接受值來初始化 T(預期的值部分)。
template < class U = T>
constexpr expected (U&& v);
意外的構造函數:
Expected<T, E> 的建構子接受 rd::unexpected 實例來初始化 E(預期的錯誤部分)。
template < class G >
constexpr expected (unexpected<G> const &);
template < class G >
constexpr expected (unexpected<G> &&);
in_place_t 建構子:
Expected<T, E> 的建構子接受 in_place 標記和參數(要轉送)來初始化 T。
template < class ... Args>
constexpr expected (std:: in_place_t , Args&&... args);
template < class U , class ... Args>
constexpr expected (std:: in_place_t , std::initializer_list<U>, Args&&... args);
unexpect_t 建構子:
Expected<T, E> 的建構子接受 rd::unexpect 標籤和參數(要轉送)來初始化 E。
template < class ... Args>
constexpr expected (rd:: unexpect_t , Args&&... args);
template < class G , class ... Args>
constexpr expected (rd:: unexpect_t , std::initializer_list<G>, Args&&... args);
複製作業:
constexpr expected& operator =(expected const &);
移動分配:
constexpr expected& operator =(expected &&);
賦值:
為預期賦值
template < class U = T>
constexpr expected& operator =(U&& rhs);
rd::意外的分配:
將錯誤分配給預期
template < class G >
constexpr expected& operator =(unexpected<G> const &);
template < class G >
constexpr expected& operator =(unexpected<G> &&);
安置:
接受建構函數的參數作為預期的新值並指派給它。
template < class ... Args>
constexpr T& emplace (Args&&... args);
template < class U , class ... Args>
constexpr T& emplace (std::initializer_list<U>, Args&&...);
交換成員函數和友元函數
// For accessing T's members
// precondition: has_value() == true
constexpr T const * operator ->() const noexcept ;
// precondition: has_value() == true
constexpr T* operator ->() noexcept ;
// Getting reference to T
// precondition: has_value() == true
constexpr T const & operator *() const & noexcept ;
// precondition: has_value() == true
constexpr T& operator *() & noexcept ;
// precondition: has_value() == true
constexpr T&& operator *() && noexcept ;
// precondition: has_value() == true
constexpr T const && operator *() const && noexcept ;
// Query if value exists
constexpr explicit operator bool () const noexcept ;
constexpr bool has_value () const noexcept ;
// Get value, if not exists throws exception rd::bad_expected_access(error())
constexpr T const & value () const &;
constexpr T& value () &;
constexpr T&& value() &&;
constexpr T const && value() const &&;
// Get error, (undefined behavior if error not exists)
constexpr E const & error () const &;
constexpr E& error () &;
constexpr E&& error() &&;
constexpr E const && error() const &&;
// Get the value, if value doesn't exist return v
template < class U >
constexpr T value_or (U&& v) const &;
template < class U >
constexpr T value_or (U&& v) &&;
進而:
F 應該是可調用的,值類型為expected,並應傳回expected,錯誤類型應為E。
template < class F >
constexpr auto and_then (F&& f) &;
template < class F >
constexpr auto and_then (F&& f) &&;
template < class F >
constexpr auto and_then (F&& f) const &;
template < class F >
constexpr auto and_then (F&& f) const &&;
或_否則:
F 應該可以使用預期的錯誤類型進行調用,並且應該返回其值類型應該是 T 的預期。
如果invoke_result_t<F, E>
是expected的任何特化(其值類型應與T相同),則如果存在值,則傳回包裝在F的invoke_result_t中的值,否則傳回呼叫f的結果。
如果invoke_result_t<F, E>
為 void,則如果有錯誤,則呼叫 F 時會發生錯誤。當前預期作為結果返回。
template < class F >
constexpr auto or_else (F&& f) &;
template < class F >
constexpr auto or_else (F&& f) &&;
template < class F >
constexpr auto or_else (F&& f) const &;
template < class F >
constexpr auto or_else (F&& f) const &&;
轉換:
F 應該可以用目前期望的值類型來呼叫。如果目前預期包含錯誤,則預期結果包含該錯誤,否則包含使用 F 呼叫目前預期值的結果。
template < class F >
constexpr auto transform (F&& f) &;
template < class F >
constexpr auto transform (F&& f) &&;
template < class F >
constexpr auto transform (F&& f) const &;
template < class F >
constexpr auto transform (F&& f) const &&;
變換錯誤:
F 應該可以用目前預期的錯誤類型來呼叫。如果目前預期包含值,則預期結果包含該值,否則包含使用 F 呼叫目前預期錯誤的結果。
template < class F >
constexpr auto transform_error (F&& f) &;
template < class F >
constexpr auto transform_error (F&& f) &&;
template < class F >
constexpr auto transform_error (F&& f) const &;
template < class F >
constexpr auto transform_error (F&& f) const &&;
template < class U , class G >
constexpr friend bool operator ==(expected const &, expected<U, G> const &);
template < class U >
constexpr friend bool operator ==(expected const &, U const &);
template < class G >
constexpr friend bool operator ==(expected const &, rd::unexpected<G> const &);
template < typename T>
class unexpected
using value_type = T
複製建構函式:
constexpr unexpected (unexpected const &);
移動構造函數:
constexpr unexpected (unexpected&&);
in_place_t 建構子:
它接受 std::in_place 標記並使用 args 建構 T。
template < typename ...Args>
constexpr unexpected (std:: in_place_t , Args&&... args);
template < typename U, typename ...Args>
constexpr unexpected (std:: in_place_t , std::initializer_list<U>, Args&&... args);
值建構函數:
用 err 構造 T。
template < typename Err>
constexpr unexpected (Err&& err);
// value(): gets the stored T value
constexpr T & value () &;
constexpr T const & value () const &;
constexpr T && value() &&;
constexpr T const && value() const &&;
template < class E2 >
friend constexpr bool operator ==(unexpected const & x, unexpected< E2 > const & y);
bad_expected_access 源自於異常。儲存錯誤值。
template < class E >
class bad_expected_access ;
E& error () & noexcept ;
E const & error () const & noexcept ;
E&& error() && noexcept ;
E const && error() const && noexcept ;
這只是一個標籤類型,表示預期的建構錯誤。
函式庫也公開了 rd::unexpect_t 類型的意外變數。
inline constexpr unexpect_t unexpect{};