C++20 を使用した単一ヘッダー std::expected 実装。
ライブラリは次の 2 つの提案を実装します。
この実装は、名前空間 rd で期待されるものを提供します。したがって、std::expected を使用する場合は、rd::expected を使用してください。
std::expected はエラー処理のメカニズムです。これは Rust の std::result と非常によく似ています。 std::expected には基本的に Result または Error のいずれかが含まれます。
例外を「常に」使用しない理由はおそらく 2 つあります。
ライブラリを作成する際、これはエラー処理に大きな問題を引き起こします。ライブラリで、エラー条件で例外をスローすることを選択した場合、ライブラリ ユーザーが選択することになります。ライブラリ内のエラー状態は、そのライブラリを使用するアプリケーションのコンテキストにおいて例外的な状況である場合もあれば、そうでない場合もあります。
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 (期待される値の部分) を初期化する値を受け入れる、期待される <T , E> のコンストラクター。
template < class U = T>
constexpr expected (U&& v);
予期しないコンストラクター:
rd::unexpected インスタンスを受け入れて E (expected のエラー部分) を初期化する Expected<T, E> のコンストラクター。
template < class G >
constexpr expected (unexpected<G> const &);
template < class G >
constexpr expected (unexpected<G> &&);
in_place_t コンストラクター:
in_place タグと引数 (転送される) を受け入れて T を初期化する Expected<T, E> のコンストラクター。
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 コンストラクター:
E を初期化するための rd::unexpect タグと引数 (転送される) を受け入れる Expected<T, 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 の値の型で呼び出し可能である必要があり、error type が E であるはずの Expected を返す必要があります。 現在の Expected のエラーを返し、エラーがある場合は、その他の関数は value で f を呼び出した結果を返します。
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 &&;
or_else:
F は、expected のエラー タイプで呼び出し可能である必要があり、値のタイプが T であるはずの Expected を返す必要があります。
invoke_result_t<F, E>
が期待される特殊化である場合 (値の型は 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 タグを受け入れ、引数を使用して 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);
値コンストラクター:
エラーを伴う 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 型の unexpect 変数も公開します。
inline constexpr unexpect_t unexpect{};