C++26 で使える(はずの) std::optional の range インターフェイスについて

[P3168R1 Give std::optional Range Support](https://wg21.link/P3168R1) が採択されそうなので、紹介します。

# 概要
`std::optional` には C++23 で[モナディックな操作を提供する変更](https://wg21.link/p0798r8)が入りましたが、またしても利便性を向上させるために range を満たすようなインターフェイスが追加されます。

# 追加されるメンバなど

この提案書での変更はそう大きくなく、追加されるものをざっと示すと以下のようになります。
```cpp
namespace std {

template <class T>
class optional {
  using iterator       = /* implementation-defined */;
  using const_iterator = /* implementation-defined */;

  constexpr iterator begin() noexcept;
  constexpr const_iterator begin() const noexcept;
  constexpr iterator end() noexcept;
  constexpr const_iterator end() const noexcept;

  /* existing members... */
};

template <class T>
constexpr bool ranges::enable_view<optional<T>> = true;

template <class T>
constexpr auto format_kind<optional<T>> = range_format::disabled;

}
```

## begin, end

```cpp
constexpr iterator begin() noexcept;
constexpr const_iterator begin() const noexcept;
constexpr iterator end() noexcept;
constexpr const_iterator end() const noexcept;
```
`std::optional` を要素数が 0 または 1 のコンテナであるかのように扱う、メモリ連続(contiguous)なイテレータを提供します。
具体的には、 `opt.has_value()` が真のとき `*opt.begin()` は `*opt` と等しく、そうでなければ `opt.begin() == opt.end()` です。

```cpp
std::optional<int> opt;

for (auto&& ref : opt) ref *= 2;
// equivalent to
opt.transform([](auto&& ref) { ref *= 2; });
```

## `std::ranges::enable_view` の特殊化

```cpp
template <class T>
constexpr bool ranges::enable_view<optional<T>> = true;
```

ある型を view として扱うためには `std::ranges::view_interface<Derived>` を継承するか `std::ranges::enable_view` を特殊化するかの二通り方法がありますが、前者は ABI 互換性を保つのに難があるため、後者の方法が取られます。

```cpp
static_assert( std::ranges::view<std::optional<int>> );  // C++23 で false, C++26 で true
```

## `std::format_kind` の特殊化

```cpp
template <class T>
constexpr auto format_kind<optional<T>> = range_format::disabled;
```

こちらは一見マイナーな変更ではありますが、[P2286R8 Formatting Ranges](https://wg21.link/P2286R8) や [P2585R1 Improve default container formatting](https://wg21.link/P2585R1) などで導入された任意の range を `std::format` でフォーマットできる機構からオプトアウトするための特殊化です。
これによって `std::formatter<std::optional<T>>` を明示的に特殊化しない限り `std::optional` が `std::format` によってフォーマットされなくなります。

# 既存のコードに対する影響について

例えば以下のような C++20 のコードについてです。

```cpp
#include <concepts>
#include <optional>
#include <ranges>

template <class T>
concept optional_like = requires(T x) {
  { x.has_value() } -> std::convertible_to<bool>;
  { *x } -> std::convertible_to<typename std::remove_cvref_t<T>::value_type const&>;
};

constexpr auto func(auto) { return 0; }                     // #0

constexpr auto func(std::ranges::range auto) { return 1; }  // #1

constexpr auto func(optional_like auto) { return 2; }       // #2

static_assert(func(std::optional<int>(42)) == 2);
```

`#0` ～ `#2` の３つのオーバーロードを持つ関数テンプレートに対しこの提案が適用される前は `std::ranges::range` と `optional-like` を同時に満たす型を想定していないために `static_assert` が通りますが、適用後はちょうど `std::optional` がその条件を満たしてしまい `#1` と `#2` とでオーバーロード解決が曖昧となりコンパイルエラーになります。
こういったトリッキーな型に対する対策が十分に取られていないコードには影響が出ますが、ある程度テスト体制が整っているならば避けやすい影響であると思われます。

# 備考
元々は [P1255R12 A view of 0 or 1 elements: views::maybe](https://wg21.link/P1255R12) といった提案において `std::views::maybe` という「要素が 0 または 1 個であるような range」が導入されようとしていましたが、そのコンセプトは `std::optional` と酷似しており、また Rust の `Option<T>` や Scala の `Option[T]` などの型がイテレーション操作を提供していることを鑑みて `std::optional<T>` に range インターフェイスを追加しようという運びになったようです。
また本提案書の著者を含めた標準化委員は [P1255R12](https://wg21.link/P1255R12) で追加を提案されていた `std::views::nullable` という *nullable* なオブジェクトを「要素が 0 または 1 個であるような range」化するアダプタ自体は支持しており、[次のリビジョン](https://wg21.link/P1255R13)では `std::views::maybe` が削除されています。

# 参照
[P3168R1 Give std::optional Range Support](https://wg21.link/P3168R1)
[P1255R12 A view of 0 or 1 elements: views::maybe](https://wg21.link/P1255R12)
[P1255R13 A view of 0 or 1 elements: views::nullable](https://wg21.link/P1255R13)