yohhoyの日記

技術的メモをしていきたい日記

std::expected<T, E>

次期C++2b(C++23)標準ライブラリに追加されるstd::expected<T, E>クラステンプレートについてメモ。

  • 従来C++例外機構(throw文+try/catch構文)に代わり、関数の演算結果(T型)またはエラー情報(E型)を “値” として返す(return)ための部品。
  • C++17 std::optional<T>型の無効値(std::nullopt)表現に代わり、具体的なエラー情報(E型)を保持可能に拡張された型。*1
  • 新しい標準ヘッダ<expected>
    • クラステンプレートexpected<T, E>、補助型unexpected<E>*2、タグunexpect、例外型bad_expected_access<E>
  • expected<T, E> == 結果Tとエラーunexpected<E>の直和型*3
    • constexpr文脈でも利用可能
    • expected<void, E>特殊化 == エラーのみを保持する
    • std::optional同様に参照型は未サポート
  • expected<T, E>型への代入/直接構築:
    • 結果/Tへ変換可能な型:r = t;または{std::in_place, t};*4
    • エラー/Eへ変換可能な型:r = std::unexpected(e);または{std::unexpect, e};
  • 保持値アクセス:
    • 結果/エラー保持判定:has_value, explicit operator bool*5
    • 結果(T型):value, value_or, operator->, operator*
    • エラー(E型):error
    • 結果未保持でのvalueメンバ関数呼び出しはstd::bad_expected_access<E>{error()}例外送出
    • 結果未保持での間接参照(->, *)アクセスは未定義動作(undefined behavior)*6
    • エラー未保持でのerrorメンバ関数呼び出しは未定義動作
  • expectedモナディック(monadic)操作はC++2bには間に合わず*7C++2c(C++26)向け提案文書 P2505 にて継続検討中。
    • C++2b標準ライブラリoptionalモナディック操作(and_then, or_elseなど)は P0789R8 が採択済み。
    • 2022-11-29追記:2022年11月会合で提案文書P2505R5が採択され、C++2b標準ライブラリにexpectedモナディック操作群が追加される。

Boost.Outcomeライブラリとの比較:

関連URL

*1:std::optional<T> ≒ std::expected<T, std::nullopt_t>

*2:C++20現在、識別子 unexpected はZombie nameとして予約されおり、expected<T, E> 導入に伴ってC++2bで蘇生(?)された初のケース。C++的ゾンビのお名前 参照。

*3:無効値 nullopt でデフォルト構築される std::optional<T> とは異なり、エラー情報を明示的に保持する std::expected<T, E> ではデフォルト構築後は結果値 T{} を保持している。

*4:https://cpprefjp.github.io/reference/utility/in_place_t.html

*5:if文の条件式などに expected<T, E> 型の値を記述することで、結果を保持しているか否かを判定可能(→id:yohhoy:20121110

*6:提案文書P0323R12 §3.14: "Using the indirection operator for an object that does not contain a value is undefined behavior. This behavior offers maximum runtime performance."

*7:https://github.com/cplusplus/papers/issues/1161#issuecomment-1027125553