最終更新日時: 2024年06月11日 22時45分38秒 (JST)
Akira Takahashi が更新

履歴 編集

class template
<expected>

# std::expected(C++23)

    namespace std {
      // プライマリテンプレート
      template<class T, class E>
      class expected;

      // T=cv void 部分特殊化テンプレート
      template<class T, class E>
        requires is_void_v<T>
      class expected<T, E>;
    }

## 概要

`expected`クラスは、任意の型`T`の値を正常値とし任意の型`E`の値をエラー値として、正常もしくはエラーいずれかの状態を取ることを値として表現できる型である。

このクラスは、ヒープからの動的メモリ確保を行わない。 実装は配置newのような機能によって、スタック領域のメモリのみを使用する。

## 適格要件

- 型`T`および型`E`は、参照型、関数型、`in_place_t`、`unexpect_t`のいずれでもないこと。
- 型`T`は`unexpected`の特殊化ではないこと。
- 型`T`が（CV修飾された）`void`型でなければ、型`T`はCpp17Destructible要件を満たすこと。
- 型`E`は非オブジェクト型、配列型、`unexpected`の特殊化、CV修飾された型のいずれでもないこと。
- 型`E`はCpp17Destructible要件を満たすこと。

## メンバ関数（プライマリテンプレート）

### 構築・破棄

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++23
`(destructor)` | デストラクタ | C++23

### 代入

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator=` | 代入演算子 | C++23
`emplace` | 正常値型のコンストラクタ引数から直接構築する | C++23
`swap` | 他の`expected`オブジェクトとデータを入れ替える | C++23

### 値の観測

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator->` | 正常値へのメンバアクセス | C++23
`operator*` | 正常値への間接参照 | C++23
`operator bool` | 正常値を保持しているかを判定する | C++23
`has_value` | 正常値を保持しているかを判定する | C++23
`value` | 正常値を取得する | C++23
`error` | エラー値を取得する | C++23
`value_or` | 正常値もしくは指定された値を取得する | C++23
`error_or` | エラー値もしくは指定された値を取得する | C++23

### モナド操作

名前 | 説明 | 対応バージョン
--- | --- | ---
`and_then` | 正常値に対して関数を適用する | C++23
`or_else` | エラー値に対して関数を適用する | C++23
`transform` | 正常値を変換する | C++23
`transform_error` | エラー値を変換する | C++23

### 比較

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator==` | 等値比較 | C++23
`operator!=` | 非等値比較 | C++23

## メンバ関数（T=cv void 部分特殊化テンプレート）

### 構築・破棄

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++23
`(destructor)` | デストラクタ | C++23

### 代入

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator=` | 代入演算子 | C++23
`emplace` | 正常値を保持する | C++23
`swap` | 他の`expected`オブジェクトとデータを入れ替える | C++23

### 値の観測

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator*` | 正常値への間接参照 | C++23
`operator bool` | 正常値を保持しているかを判定する | C++23
`has_value` | 正常値を保持しているかを判定する | C++23
`value` | 正常値を取得する | C++23
`error` | エラー値を取得する | C++23
`error_or` | エラー値もしくは指定された値を取得する | C++23

（`expected<cv void, E>` 部分特殊化では、演算子オーバーロード `operator->`およびメンバ関数`value_or`は提供されない。）

### モナド操作

名前 | 説明 | 対応バージョン
--- | --- | ---
`and_then` | 正常値に対して関数を適用する | C++23
`or_else` | エラー値に対して関数を適用する | C++23
`transform` | 正常値を変換する | C++23
`transform_error` | エラー値を変換する | C++23

### 比較

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator==` | 等値比較 | C++23
`operator!=` | 非等値比較 | C++23

## メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`value_type` | 正常値の型`T` | C++23
`error_type` | エラー値の型`E` | C++23
`unexpected_type` | `unexpected<E>` | C++23
`template<class U> rebind` | `expected<U, error_type>` | C++23

## 非メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`swap` | 2つの`expected<T, E>`オブジェクトを入れ替える | C++23
`swap` | 2つの`expected<cv void, E>`オブジェクトを入れ替える | C++23

## 例

    #include <expected>
    #include <iomanip>
    #include <iostream>
    #include <string>

    // 整数除算
    std::expected<int, std::string> idiv(int a, int b)
    {
      if (b == 0) {
        return std::unexpected{"divide by zero"};
      }
      if (a % b != 0) {
        return std::unexpected{"out of domain"};
      }
      return a / b;
    }

    void dump_result(const std::expected<int, std::string>& v)
    {
      if (v) {
        std::cout << *v << std::endl;
      } else {
        std::cout << std::quoted(v.error()) << std::endl;
      }
    }

    int main()
    {
      dump_result(idiv(10, 2));
      dump_result(idiv(10, 3));
      dump_result(idiv(10, 0));
    }

### 出力

    5
    "out of domain"
    "divide by zero"

## バージョン

### 言語

- C++23

### 処理系

- Clang: 16.0 ✅
- GCC: 12.1 ✅
- ICC: ??
- Visual C++: ??

## 関連項目

- `unexpected`
- `optional`

## 参照

- P0323R12 std::expected
- P2505R5 Monadic Functions for `std::expected`