最終更新日時: 2026年04月07日 15時36分39秒 (JST)
Akira Takahashi が更新

履歴 編集

function template
<optional>

# std::optional::or_else(C++23)

    // optional<T>版のオーバーロード
    template<class F> constexpr optional or_else(F&& f) const &; // (1) C++23
    template<class F> constexpr optional or_else(F&& f) &&;      // (2) C++23

    // optional<T&>版のオーバーロード (C++26)
    template<class F> constexpr optional or_else(F&& f) const;   // (3) C++26

## 概要

有効値を保持していれば、なにもしない。 有効値を保持していなければ、`f()`の呼び出し結果を`optional`として返す。

- (1) : `*this`が`const`左辺値の場合
- (2) : `*this`が右辺値の場合
- (3) : `optional<T&>`の場合

`optional<T>`では (1), (2) が定義され、`optional<T&>`では (3) のみが定義される。

実際には複数オーバーロードが提供されるが、大まかには下記シグニチャのようにみなせる。 `or_else`へは、空の引数リストをとり`std::optional<T>`へ変換可能な`Return`型を返す関数や関数オブジェクトを与える。

    template <class T>
    class optional {
      template <class Return>
      std::optional<T> or_else(function<Return()> func);
    };

## テンプレートパラメータ制約

- (1) : `F`は`invocable<>`のモデル、かつ`T`は`copy_constructible`のモデルであること
- (2) : `F`は`invocable<>`のモデル、かつ`T`は`move_constructible`のモデルであること
- (3) : `F`は`invocable<>`のモデル、かつ`T`は`copy_constructible`のモデルであること

## 適格要件

`is_same_v<remove_cvref_t<invoke_result_t<F>>, optional>`が`true`であること

## 効果

- (1), (3) : 次と等価

      if (*this) {
        return *this;
      } else {
        return std::forward<F>(f)();
      }

- (2) : 次と等価

      if (*this) {
        return std::move(*this);
      } else {
        return std::forward<F>(f)();
      }

## 備考

`or_else`は、メソッドチェーンをサポートするモナド風(monadic)操作として導入された。

## 例

### 基本的な使い方

    #include <cassert>
    #include <optional>

    std::optional<int> defvalue()
    {
      return 42;
    }

    int main()
    {
      std::optional<int> o1 = 1;
      assert(o1.or_else(defvalue).value() == 1);

      std::optional<int> o2 = std::nullopt;
      assert(o2.or_else(defvalue).value() == 42);
    }

#### 出力

### メソッドチェインとしての使い方

    #include <cassert>
    #include <charconv>
    #include <optional>
    #include <string_view>

    std::optional<int> parse(std::string_view sv, int base, std::string_view prefix = "")
    {
      if (!prefix.empty() && !sv.starts_with(prefix))
        return std::nullopt;
      int n{};
      auto [ptr, ec] = std::from_chars(sv.data() + prefix.size(), sv.data() + sv.size(), n, base);
      if (ec == std::errc{} && ptr == sv.data() + sv.size())
        return n;
      else
        return std::nullopt;
    }

    std::optional<int> parse_digit(std::string_view sv)
    {
      return parse(sv, 2, "0b")
        .or_else([sv] { return parse(sv, 10); })
        .or_else([sv] { return parse(sv, 16, "0x"); });
    }

    int main()
    {
      assert(parse_digit("0b11") == std::optional(3));
      assert(parse_digit("11") == std::optional(11));
      assert(parse_digit("0x11") == std::optional(17));
      assert(parse_digit("x") == std::nullopt);
    }

#### 出力

## バージョン

### 言語

- C++23

### 処理系

- Clang: ??
- GCC: ??
- ICC: ??
- Visual C++: ??

## 関連項目

- `and_then`
- `transform`
- `value_or`

## 参照

- P0798R8 Monadic operations for std::optional
- P2988R12 `std::optional<T&>`
  - C++26で参照型`T&`に対する部分特殊化を追加