Skip to content

Commit

Permalink
optional: P0798R8 and_then/transform/or_else追加(#1057)
Browse files Browse the repository at this point in the history
  • Loading branch information
yohhoy committed Jan 19, 2023
1 parent c73a954 commit 98315ac
Show file tree
Hide file tree
Showing 5 changed files with 350 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lang/cpp23.md
Expand Up @@ -203,7 +203,7 @@ C++23とは、2023年中に改訂される予定の、C++バージョンの通
- [`std::visit()`](/reference/variant/visit.md)に指定できるバリアントオブジェクトを、直接的な「[`std::variant`](/reference/variant/variant.md)型の特殊化であること」という制約を緩和し、[`std::variant`](/reference/variant/variant.md)から派生した型も許可
- [`<utility>`](/reference/utility.md)に、列挙値を基底型に変換する[`std::to_underlying()`](/reference/utility/to_underlying.md)関数を追加
- [`<utility>`](/reference/utility.md)に、 (主に) メンバ変数を転送するため、指定された型の`const`性と参照修飾で引数を転送する[`std::forward_like()`](/reference/utility/forward_like.md)関数を追加
- [`std::optional`](/reference/optional/optional.md)クラスにモナド操作としてメンバ関数[`and_then()`](/reference/optional/optional/and_then.md.nolink)[`transform()`](/reference/optional/optional/transform.md.nolink)[`or_else()`](/reference/optional/optional/or_else.md.nolink)を追加
- [`std::optional`](/reference/optional/optional.md)クラスにモナド操作としてメンバ関数[`and_then()`](/reference/optional/optional/and_then.md)[`transform()`](/reference/optional/optional/transform.md)[`or_else()`](/reference/optional/optional/or_else.md)を追加
- 到達しないパスであることを表明する関数[`std::unreachable()`](/reference/utility/unreachable.md)を追加
- [`std::bitset`](/reference/bitset/bitset.md)クラスをさらに`constexpr`対応

Expand Down
10 changes: 10 additions & 0 deletions reference/optional/optional.md
Expand Up @@ -78,6 +78,15 @@ namespace std {
| [`value_or`](optional/value_or.md) | 有効値もしくは指定された無効値を取得する | C++17 |
### モナド操作
| 名前 | 説明 | 対応バージョン |
|------|------|----------------|
| [`and_then`](optional/and_then.md) | 有効値に対して関数を適用する | C++23 |
| [`transform`](optional/transform.md) | 有効値を変換する | C++23 |
| [`or_else`](optional/or_else.md) | 無効値に対して関数を適用する | C++23 |
## メンバ型
| 名前 | 説明 | 対応バージョン |
Expand Down Expand Up @@ -201,3 +210,4 @@ error
- [P0307R2 Making Optional Greater Equal Again](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0307r2.pdf)
- [P0504R0 Revisiting in-place tag types for `any`/`optional`/`variant`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0504r0.html)
- [LWG Issue 3196. `std::optional<T>` is ill-formed is `T` is an array](https://wg21.cmeerw.net/lwg/issue3196)
- [P0798R8 Monadic operations for std::optional](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html)
123 changes: 123 additions & 0 deletions reference/optional/optional/and_then.md
@@ -0,0 +1,123 @@
# and_then
* optional[meta header]
* function template[meta id-type]
* std[meta namespace]
* optional[meta class]
* cpp23[meta cpp]

```cpp
template <class F> constexpr auto and_then(F&& f) &; // (1)
template <class F> constexpr auto and_then(F&& f) &&; // (2)
template <class F> constexpr auto and_then(F&& f) const&; // (3)
template <class F> constexpr auto and_then(F&& f) const&&; // (4)
```
## 概要
有効値を保持していれば、値に対して`f`を適用した結果を`optional`として返す。
有効値を保持していなければ、[`std::nullopt`](../nullopt_t.md)を返す。
実際には複数オーバーロードが提供されるが、大まかには下記シグニチャのようにみなせる。
`and_then`へは、引数リストに1個の`T`型をとり`std::optional<Return>`型を返す関数や関数オブジェクトを与える。
```cpp
template <class T>
class optional {
template <class Return>
std::optional<Return> and_then(function<std::optional<Return>(T)> func);
};
```
* function[link /reference/functional/function.md]


## 適格要件
説明用の`U`型を次の通りとする:

- (1), (3) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(`[`value()`](value.md)`)>`
- (2), (4) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(`[`std​::​move`](/reference/utility/move.md)`(`[`value()`](value.md)`))>`

[`remove_cvref_t`](/reference/type_traits/remove_cvref.md)`<U>``optional`の特殊化であること


## 効果
- (1), (3) : 次と等価

```cpp
if (*this) {
return invoke(std::forward<F>(f), value());
} else {
return remove_cvref_t<U>();
}
```

- (2), (4) : 次と等価

```cpp
if (*this) {
return invoke(std::forward<F>(f), std::move(value()));
} else {
return remove_cvref_t<U>();
}
```


## 備考
`and_then`は、メソッドチェーンをサポートするモナド風(monadic)操作として導入された。
関数型プログラミングの文脈における Monadic Bind 操作に対応する。


##
```cpp example
#include <cassert>
#include <optional>

// 正数なら2倍/それ以外は無効値を返す関数
std::optional<int> twice(int n)
{
if (0 < n) {
return n * 2;
} else {
return std::nullopt;
}
}

int main()
{
std::optional<int> o1 = 2;
assert(o1.and_then(twice).value() == 4);

std::optional<int> o2 = -1;
assert(not o2.and_then(twice).has_value());

std::optional<int> o3 = std::nullopt;
assert(not o3.and_then(twice).has_value());
}
```
* and_then[color ff0000]
* std::nullopt[link ../nullopt_t.md]
* value()[link value.md]
* has_value()[link has_value.md]
### 出力
```
```
## バージョン
### 言語
- C++23
### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??
## 関連項目
- [`transform`](transform.md)
- [`or_else`](or_else.md)
## 参照
- [P0798R8 Monadic operations for std::optional](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html)
112 changes: 112 additions & 0 deletions reference/optional/optional/or_else.md
@@ -0,0 +1,112 @@
# or_else
* optional[meta header]
* function template[meta id-type]
* std[meta namespace]
* optional[meta class]
* cpp23[meta cpp]

```cpp
template<class F> constexpr optional or_else(F&& f) const &; // (1)
template<class F> constexpr optional or_else(F&& f) &&; // (2)
```
## 概要
有効値を保持していれば、なにもしない。
有効値を保持していなければ、`f()`の呼び出し結果を`optional`として返す。
実際には複数オーバーロードが提供されるが、大まかには下記シグニチャのようにみなせる。
`or_else`へは、空の引数リストをとり`std::optional<T>`へ変換可能な`Return`型を返す関数や関数オブジェクトを与える。
```cpp
template <class T>
class optional {
template <class Return>
std::optional<T> or_else(function<Return()> func);
};
```
* function[link /reference/functional/function.md]


## テンプレートパラメータ制約
- (1) : `F`[`invocable<>`](/reference/concepts/invocable.md)のモデル、かつ`T`[`copy_constructible`](/reference/concepts/copy_constructible.md)のモデルであること
- (2) : `F`[`invocable<>`](/reference/concepts/invocable.md)のモデル、かつ`T`[`move_constructible`](/reference/concepts/move_constructible.md)のモデルであること


## 適格要件
[`is_same_v`](/reference/type_traits/is_same.md)`<`[`remove_cvref_t`](/reference/type_traits/remove_cvref.md)`<`[`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F>>, optional>``true`であること


## 効果
- (1) : 次と等価

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

- (2) : 次と等価

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


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


##
```cpp example
#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);
}
```
* or_else[color ff0000]
* std::nullopt[link ../nullopt_t.md]
* value()[link value.md]


### 出力
```
```


## バージョン
### 言語
- C++23

### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??


## 関連項目
- [`and_then`](and_then.md)
- [`transform`](transform.md)
- [`value_or`](value_or.md)


## 参照
- [P0798R8 Monadic operations for std::optional](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html)
104 changes: 104 additions & 0 deletions reference/optional/optional/transform.md
@@ -0,0 +1,104 @@
# transform
* optional[meta header]
* function template[meta id-type]
* std[meta namespace]
* optional[meta class]
* cpp23[meta cpp]

```cpp
template <class F> constexpr auto transform(F&& f) &; // (1)
template <class F> constexpr auto transform(F&& f) &&; // (2)
template <class F> constexpr auto transform(F&& f) const&; // (3)
template <class F> constexpr auto transform(F&& f) const&&; // (4)
```
## 概要
有効値を保持していれば、値に対して`f`を適用した結果を`optional`に格納して返す。
有効値を保持していなければ、[`std::nullopt`](../nullopt_t.md)を返す。
実際には複数オーバーロードが提供されるが、大まかには下記シグニチャのようにみなせる。
`transform`へは、引数リストに1個の`T`型をとり`Return`型を返す関数や関数オブジェクトを与える。
```cpp
template <class T>
class optional {
template <class Return>
std::optional<Return> transform(function<Return(T)> func);
};
```
* function[link /reference/functional/function.md]


説明用の`U`型を次の通りとする:

- (1), (3) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(`[`value()`](value.md)`)>`
- (2), (4) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(`[`std​::​move`](/reference/utility/move.md)`(`[`value()`](value.md)`))>`


## 適格要件
- (1), (3) :
- `U`型は[`in_place_t`](/reference/utility/in_place_t.md), [`nullopt_t`](nullopt_t.md)いずれでもなく、非配列オブジェクト型であること。
- ある変数`u`の宣言 `U u(`[`invoke`](/reference/functional/invoke.md)`(`[`std::forward`](/reference/utility/forward.md)`<F>(f),` [`value()`](value.md)`));` が妥当であること。
- (2), (4) :
- `U`型は[`in_place_t`](/reference/utility/in_place_t.md), [`nullopt_t`](nullopt_t.md)いずれでもなく、非配列オブジェクト型であること。
- ある変数`u`の宣言 `U u(`[`invoke`](/reference/functional/invoke.md)`(`[`std::forward`](/reference/utility/forward.md)`<F>(f),` [`std​::​move`](/reference/utility/move.md)`(`[`value()`](value.md)`)));` が妥当であること。


## 効果
- (1), (3) : `*this`が有効値を保持するときは、[`invoke`](/reference/functional/invoke.md)`(`[`std::forward`](/reference/utility/forward.md)`<F>(f),` [`value()`](value.md)`)`で非リスト初期化した`optional<U>`オブジェクトを返す。有効値を保持しないときは、`optional<U>()`を返す。
- (2), (4) : `*this`が有効値を保持するときは、[`invoke`](/reference/functional/invoke.md)`(`[`std::forward`](/reference/utility/forward.md)`<F>(f),` [`std​::​move`](/reference/utility/move.md)`(`[`value()`](value.md)`))`で非リスト初期化した`optional<U>`オブジェクトを返す。有効値を保持しないときは、`optional<U>()`を返す。


## 備考
`transform`は、メソッドチェーンをサポートするモナド風(monadic)操作として導入された。
関数型プログラミングの文脈における Functor Map 操作に対応する。


##
```cpp example
#include <cassert>
#include <optional>

int twice(int n)
{
return n * 2;
}

int main()
{
std::optional<int> o1 = 2;
assert(o1.transform(twice).value() == 4);

std::optional<int> o2 = std::nullopt;
assert(not o2.transform(twice).has_value());
}
```
* transform[color ff0000]
* std::nullopt[link ../nullopt_t.md]
* value()[link value.md]
* has_value()[link has_value.md]
### 出力
```
```
## バージョン
### 言語
- C++23
### 処理系
- [Clang](/implementation.md#clang): ??
- [GCC](/implementation.md#gcc): ??
- [ICC](/implementation.md#icc): ??
- [Visual C++](/implementation.md#visual_cpp): ??
## 関連項目
- [`and_then`](and_then.md)
- [`or_else`](or_else.md)
## 参照
- [P0798R8 Monadic operations for std::optional](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html)

0 comments on commit 98315ac

Please sign in to comment.