最終更新日時(UTC):
が更新

履歴 編集

class template
<optional>

std::optional(C++17)

namespace std {
  template <class T>
  class optional;

  // 参照に対する部分特殊化 (C++26)
  template <class T>
  class optional<T&>;


  // viewコンセプトを有効化する (C++26)
  template<class T>
  constexpr bool ranges::enable_view<optional<T>> = true;

  // std::formatによるフォーマットを無効化する (C++26)
  template<class T>
  constexpr auto format_kind<optional<T>> = range_format::disabled;

  // borrowed_rangeコンセプトを有効化する (C++26)
  template<class T>
  constexpr bool ranges::enable_borrowed_range<optional<T&>> = true;
}

概要

optionalクラスは、任意の型Tの値を有効値として、あらゆる型に共通の無効値状態を表現できる型である。

このクラスには、大きく2つの用途がある:

  1. オブジェクトの初期化タイミングを遅延させる
  2. エラー報告のために、あらゆる型に共通の無効値表現を持たせる

オブジェクトは定義した時点で初期化が行われるが、optionalクラスはその初期化タイミングを遅延させるために使用できる。この用途には、std::shared_ptrのようなスマートポインタを使用することもできるが、このクラスは動的メモリ確保を行わないため、リソース管理ではなく初期化タイミングを遅延させるだけであれば、このクラスの方が適している。

エラー報告について、このクラスを使用しない場合、従来の方法として有効値と無効値は、以下のように表現されていた:

  • int型の場合、0以上の値を有効な値とし、エラーが起きたら負数を代入する
  • ポインタの場合、オブジェクトへのポインタを有効な値とし、どこも指さないヌルポインタを無効値として代入する

このような有効値と無効値の表現は、変数単位もしくはAPI・ライブラリ単位での仕様である。optionalクラスでは、nulloptという特殊な定数を無効値とし、あらゆる型に共通の無効状態を持たせられるようになっている。

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

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

プライマリテンプレートoptional<T>の型Tが以下のいずれかに該当してはならない:

また、型Tstd::destructible要件を満たすこと。

参照に対する部分特殊化 (C++26)

このクラスは、optional<T&>のように参照を保持できる。内部的にはTへのポインタとして保持され、代入時には参照先を再束縛 (rebind) する。

optional<T&>は以下の特徴をもつ:

  • ダングリング参照を防ぐため、一時オブジェクトから構築するオーバーロードは削除定義される
  • 代入は参照先の再束縛 (rebind) を行う(参照先オブジェクトへの代入ではない)
  • emplace()は参照先の再束縛を行う意味論であるため、可変長引数版やstd::initializer_list版はなく、単一引数のみ受け取る
  • optional<T&>はトリビアルコピー可能 (trivially copyable) である
  • モナド操作 (and_then(), transform(), or_else()) も使用可能

備考

このクラスの前身となったBoost Optional Libraryでは、optional<int&>のように左辺値参照を要素型とした場合に、無効値の領域を最適化する機能が入っていた。

メンバ関数

構築・破棄

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

代入

名前 説明 対応バージョン
operator= 代入演算子 C++17
emplace 要素型のコンストラクタ引数から直接構築する C++17
swap 他のoptionalオブジェクトとデータを入れ替える C++17
reset 有効値を保持していない状態にする C++17

イテレータ

名前 説明 対応バージョン
begin optionalをrangeとした時の先頭要素を指すイテレータを取得する C++26
end optionalをrangeとした時の末尾要素の次を指すイテレータを取得する C++26

値の観測

名前 説明 対応バージョン
operator* 間接参照 C++17
operator-> メンバアクセス C++17
operator bool 有効な値を保持しているかを判定する C++17
has_value 有効な値を保持しているかを判定する C++17
value 有効値を取得する C++17
value_or 有効値もしくは指定された無効値を取得する C++17

モナド操作

名前 説明 対応バージョン
and_then 有効値に対して関数を適用する C++23
transform 有効値を変換する C++23
or_else 無効値に対して関数を適用する C++23

メンバ型

名前 説明 対応バージョン
value_type 要素型T C++17
iterator 実装定義のイテレータ型。contiguous_iteratorrandom_access_iterator、constexprイテレータのモデルであり、コンテナのイテレータに対するすべての要件を満たす C++26
const_iterator 実装定義の読み取り専用イテレータ型。contiguous_iteratorrandom_access_iterator、constexprイテレータのモデルであり、コンテナのイテレータに対するすべての要件を満たす C++26

非メンバ関数

ヘルパ関数

名前 説明 対応バージョン
make_optional 有効な値を保持するoptionalオブジェクトを構築する C++17

値の入れ替え

名前 説明 対応バージョン
swap 2つのoptionalオブジェクトを入れ替える C++17

比較演算子

名前 説明 対応バージョン
operator== 等値比較 C++17
operator!= 非等値比較 C++17
operator<=> 三方比較 C++20
operator< 左辺が右辺より小さいかを判定する C++17
operator<= 左辺が右辺以下かを判定する C++17
operator> 左辺が右辺より大きいかを判定する C++17
operator>= 左辺が右辺以上かを判定する C++17

推論補助

名前 説明 対応バージョン
(deduction_guide) クラステンプレートの推論補助 C++17

ハッシュサポート

名前 説明 対応バージョン
template <class T> struct hash; hashクラスの先行宣言 C++17
template <class T> struct hash<optional<T>>; hashクラスのoptionalに対する特殊化 C++17

#include <iostream>
#include <optional>

// 除算をする関数。
// ゼロ割りを試みた場合、無効値が返る
std::optional<int> safe_divide(int a, int b)
{
  if (b == 0)
    return std::nullopt;

  return a / b;
}

int main()
{
  // 9/3を計算する
  std::optional<int> result1 = safe_divide(9, 3);
  if (result1) { // 計算に成功した場合、有効値が返る
    int x = result1.value(); // 有効値を取り出す
    std::cout << x << std::endl;
  }

  // 3/0の計算を試みる
  std::optional<int> result2 = safe_divide(3, 0);
  if (!result2) { // 計算に失敗した場合、無効値が返る
    std::cout << "error" << std::endl;
  }
}

出力

3
error

参照型を保持する例 (C++26)

#include <print>
#include <optional>
#include <map>
#include <string>

// コンテナからの要素検索。見つからない場合は無効値を返す
std::optional<const std::string&>
  find_value(const std::map<int, std::string>& m, int key)
{
  auto it = m.find(key);
  if (it != m.end()) {
    return it->second;  // 要素への参照を返す (コピーは発生しない)
  }
  return std::nullopt;
}

int main()
{
  std::map<int, std::string> m = {
    {1, "Alice"},
    {2, "Bob"},
    {3, "Charlie"}
  };

  // 値が見つかった場合
  if (auto name = find_value(m, 2)) {
    // コピーではなく参照を保持しているため、効率的にアクセスできる
    std::println("{}", name.value());
  }

  // 値が見つからなかった場合
  if (auto name = find_value(m, 99); !name) {
    std::println("not found");
  }

  // モナド操作との組み合わせ
  auto result = find_value(m, 1)
    .transform([](const std::string& s) { return s.size(); })
    .value_or(0u);
  std::println("{}", result);
}

出力

Bob
not found
5

バージョン

言語

  • C++17

処理系

参照