Skip to content

Commit 657e3a9

Browse files
committed
optional : C++26での参照への部分特殊化に対応 #1498
1 parent 321f8d1 commit 657e3a9

File tree

12 files changed

+312
-45
lines changed

12 files changed

+312
-45
lines changed

reference/optional/optional.md

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ namespace std {
99
template <class T>
1010
class optional;
1111

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

1317
// viewコンセプトを有効化する (C++26)
1418
template<class T>
@@ -17,6 +21,10 @@ namespace std {
1721
// std::formatによるフォーマットを無効化する (C++26)
1822
template<class T>
1923
constexpr auto format_kind<optional<T>> = range_format::disabled;
24+
25+
// borrowed_rangeコンセプトを有効化する (C++26)
26+
template<class T>
27+
constexpr bool ranges::enable_borrowed_range<optional<T&>> = true;
2028
}
2129
```
2230
@@ -41,7 +49,7 @@ namespace std {
4149
4250
4351
## テンプレートパラメータ制約
44-
`T`が以下のいずれかに該当してはならない:
52+
プライマリテンプレート`optional<T>`の型`T`が以下のいずれかに該当してはならない:
4553
4654
- 参照型
4755
- (CV修飾された)[`std::in_place_t`](/reference/utility/in_place_t.md)
@@ -50,11 +58,21 @@ namespace std {
5058
また、型`T`は[`std::destructible`](/reference/concepts/destructible.md)要件を満たすこと。
5159
5260
61+
## 参照に対する部分特殊化 (C++26)
62+
このクラスは、`optional<T&>`のように参照を保持できる。内部的には`T`へのポインタとして保持され、代入時には参照先を再束縛 (rebind) する。
63+
64+
`optional<T&>`は以下の特徴をもつ:
65+
66+
- ダングリング参照を防ぐため、一時オブジェクトから構築するオーバーロードは削除定義される
67+
- 代入は参照先の再束縛 (rebind) を行う(参照先オブジェクトへの代入ではない)
68+
- [`emplace()`](optional/emplace.md)は参照先の再束縛を行う意味論であるため、可変長引数版や[`std::initializer_list`](/reference/initializer_list/initializer_list.md)版はなく、単一引数のみ受け取る
69+
- `optional<T&>`はトリビアルコピー可能 (trivially copyable) である
70+
- モナド操作 ([`and_then()`](optional/and_then.md), [`transform()`](optional/transform.md), [`or_else()`](optional/or_else.md)) も使用可能
71+
72+
5373
## 備考
5474
このクラスの前身となった[Boost Optional Library](https://boost.org/libs/optional)では、`optional<int&>`のように左辺値参照を要素型とした場合に、無効値の領域を最適化する機能が入っていた。
5575
56-
標準ライブラリの`optional`クラスには現在、参照を持たせることはできない。
57-
5876
5977
## メンバ関数
6078
### 構築・破棄
@@ -199,6 +217,64 @@ error
199217
```
200218

201219

220+
### 参照型を保持する例 (C++26)
221+
```cpp example
222+
#include <print>
223+
#include <optional>
224+
#include <map>
225+
#include <string>
226+
227+
// コンテナからの要素検索。見つからない場合は無効値を返す
228+
std::optional<const std::string&>
229+
find_value(const std::map<int, std::string>& m, int key)
230+
{
231+
auto it = m.find(key);
232+
if (it != m.end()) {
233+
return it->second; // 要素への参照を返す (コピーは発生しない)
234+
}
235+
return std::nullopt;
236+
}
237+
238+
int main()
239+
{
240+
std::map<int, std::string> m = {
241+
{1, "Alice"},
242+
{2, "Bob"},
243+
{3, "Charlie"}
244+
};
245+
246+
// 値が見つかった場合
247+
if (auto name = find_value(m, 2)) {
248+
// コピーではなく参照を保持しているため、効率的にアクセスできる
249+
std::println("{}", name.value());
250+
}
251+
252+
// 値が見つからなかった場合
253+
if (auto name = find_value(m, 99); !name) {
254+
std::println("not found");
255+
}
256+
257+
// モナド操作との組み合わせ
258+
auto result = find_value(m, 1)
259+
.transform([](const std::string& s) { return s.size(); })
260+
.value_or(0u);
261+
std::println("{}", result);
262+
}
263+
```
264+
* std::nullopt[link nullopt_t.md]
265+
* std::println[link /reference/print/println.md]
266+
* name.value()[link optional/value.md]
267+
* .transform[link optional/transform.md]
268+
* .value_or[link optional/value_or.md]
269+
270+
#### 出力
271+
```
272+
Bob
273+
not found
274+
5
275+
```
276+
277+
202278
## バージョン
203279
### 言語
204280
- C++17
@@ -230,3 +306,7 @@ error
230306
- [P0504R0 Revisiting in-place tag types for `any`/`optional`/`variant`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0504r0.html)
231307
- [LWG Issue 3196. `std::optional<T>` is ill-formed is `T` is an array](https://wg21.cmeerw.net/lwg/issue3196)
232308
- [P0798R8 Monadic operations for std::optional](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html)
309+
- [P2988R12 `std::optional<T&>`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2988r12.pdf)
310+
- C++26で参照型`T&`に対する部分特殊化を追加
311+
- [P3836R2 `optional<T&>` Should Be Trivially Copyable](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3836r2.html)
312+
- C++26で`optional<T&>`がトリビアルコピー可能であることを保証

reference/optional/optional/and_then.md

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,28 @@
66
* cpp23[meta cpp]
77

88
```cpp
9-
template <class F> constexpr auto and_then(F&& f) &; // (1)
10-
template <class F> constexpr auto and_then(F&& f) &&; // (2)
11-
template <class F> constexpr auto and_then(F&& f) const&; // (3)
12-
template <class F> constexpr auto and_then(F&& f) const&&; // (4)
9+
// optional<T>版のオーバーロード
10+
template <class F> constexpr auto and_then(F&& f) &; // (1) C++23
11+
template <class F> constexpr auto and_then(F&& f) &&; // (2) C++23
12+
template <class F> constexpr auto and_then(F&& f) const&; // (3) C++23
13+
template <class F> constexpr auto and_then(F&& f) const&&; // (4) C++23
14+
15+
// optional<T&>版のオーバーロード (C++26)
16+
template <class F> constexpr auto and_then(F&& f) const; // (5) C++26
1317
```
1418
1519
## 概要
1620
有効値を保持していれば、値に対して`f`を適用した結果を`optional`として返す。
1721
有効値を保持していなければ、[`std::nullopt`](../nullopt_t.md)を返す。
1822
23+
- (1) : `*this`が非`const`左辺値の場合
24+
- (2) : `*this`が非`const`右辺値の場合
25+
- (3) : `*this`が`const`左辺値の場合
26+
- (4) : `*this`が`const`右辺値の場合
27+
- (5) : `optional<T&>`の場合
28+
29+
`optional<T>`では (1)~(4) が定義され、`optional<T&>`では (5) のみが定義される。
30+
1931
実際には複数オーバーロードが提供されるが、大まかには下記シグニチャのようにみなせる。
2032
`and_then`へは、引数リストに1個の`T`型をとり`std::optional<Return>`型を返す関数や関数オブジェクトを与える。
2133
@@ -34,6 +46,7 @@ class optional {
3446

3547
- (1), (3) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(`[`value()`](value.md)`)>`
3648
- (2), (4) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(`[`std::move`](/reference/utility/move.md)`(`[`value()`](value.md)`))>`
49+
- (5) : [`invoke_result_t`](/reference/type_traits/invoke_result.md)`<F, decltype(*val)>` (説明専用メンバ`val``T*`型)
3750

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

@@ -64,6 +77,17 @@ class optional {
6477
* std::move[link /reference/utility/move.md]
6578
* value()[link value.md]
6679

80+
- (5) : 次と等価
81+
82+
```cpp
83+
if (*this) {
84+
return invoke(std::forward<F>(f), *val);
85+
} else {
86+
return remove_cvref_t<U>();
87+
}
88+
```
89+
* invoke[link /reference/functional/invoke.md]
90+
6791

6892
## 備考
6993
`and_then`は、メソッドチェーンをサポートするモナド風(monadic)操作として導入された。
@@ -126,3 +150,5 @@ int main()
126150
127151
## 参照
128152
- [P0798R8 Monadic operations for std::optional](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0798r8.html)
153+
- [P2988R12 `std::optional<T&>`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2988r12.pdf)
154+
- C++26で参照型`T&`に対する部分特殊化を追加

reference/optional/optional/emplace.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* cpp17[meta cpp]
77

88
```cpp
9+
// optional<T>版のオーバーロード
910
template <class... Args>
1011
T& emplace(Args&&... args); // (1) C++17
1112
template <class... Args>
@@ -15,24 +16,32 @@ template <class U, class... Args>
1516
T& emplace(std::initializer_list<U> il, Args&&... args); // (2) C++17
1617
template <class U, class... Args>
1718
constexpr T& emplace(std::initializer_list<U> il, Args&&... args); // (2) C++23
19+
20+
// optional<T&>版のオーバーロード (C++26)
21+
template <class U>
22+
constexpr T& emplace(U&& u) noexcept(see below); // (3) C++26
1823
```
1924
2025
## 概要
2126
要素型のコンストラクタ引数から直接構築する。
2227
2328
- (1) : 可変個の引数をとり、それを型`T`のコンストラクタ引数として渡して、この関数内で型`T`の有効値を構築して保持する
2429
- (2) : 初期化子リストと可変個の引数をとり、それらを型`T`のコンストラクタ引数として渡して、この関数内で型`T`の有効値を構築して保持する
30+
- (3) : `optional<T&>`の参照先を再束縛する。変換可能な単一引数を受け取る
31+
32+
`optional<T>`では (1), (2) が定義され、`optional<T&>`では (3) のみが定義される。
2533
2634
27-
## 要件
35+
## テンプレートパラメータ制約
2836
- (1) : [`is_constructible_v`](/reference/type_traits/is_constructible.md)`<T, Args&&...> == true`であること
37+
- (3) : [`is_constructible_v`](/reference/type_traits/is_constructible.md)`<T&, U> == true`であり、[`reference_constructs_from_temporary_v`](/reference/type_traits/reference_constructs_from_temporary.md)`<T&, U> == false`であること
2938
3039
3140
## 効果
32-
まず、共通の動作として、[`reset()`](reset.md)メンバ関数を呼び出す
33-
34-
- (1) : 型`T`の有効値を、[`std::forward<Args>`](/reference/utility/forward.md)`(args)...`を引数として構築する
35-
- (2) : 型`T`の有効値を、`il`と[`std::forward<Args>`](/reference/utility/forward.md)`(args)...`を引数として構築する
41+
- (1), (2) : まず[`reset()`](reset.md)メンバ関数を呼び出す
42+
- (1) : 型`T`の有効値を、[`std::forward<Args>`](/reference/utility/forward.md)`(args)...`を引数として構築する
43+
- (2) : 型`T`の有効値を、`il`と[`std::forward<Args>`](/reference/utility/forward.md)`(args)...`を引数として構築する
44+
- (3) : 参照先を`u`に再束縛する
3645
3746
3847
## 戻り値
@@ -49,6 +58,7 @@ constexpr T& emplace(std::initializer_list<U> il, Args&&... args); // (2) C++23
4958
5059
## 備考
5160
- (2) : このオーバーロードは主に、コンテナをアロケータ付きで、初期化子リスト代入するためにある
61+
- (3) : 一時オブジェクトから参照を構築するとダングリングになるケースでは、このオーバーロードは削除定義される
5262
5363
5464
## 例
@@ -114,3 +124,5 @@ int main()
114124
- [LWG Issue 2857. {`variant`,`optional`,`any`}`::emplace` should return the constructed value](https://wg21.cmeerw.net/lwg/issue2857)
115125
- [P0084R2 Emplace Return Type (Revision 2)](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf)
116126
- [P2231R1 Missing `constexpr` in `std::optional` and `std::variant`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2231r1.html)
127+
- [P2988R12 `std::optional<T&>`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2988r12.pdf)
128+
- C++26で参照型`T&`に対する部分特殊化を追加

reference/optional/optional/op_arrow.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,32 @@
66
* cpp17[meta cpp]
77

88
```cpp
9-
constexpr const T* operator->() const;
10-
constexpr T* operator->();
9+
// optional<T>版のオーバーロード
10+
constexpr const T* operator->() const; // (1) C++17
11+
constexpr T* operator->(); // (2) C++17
12+
13+
// optional<T&>版のオーバーロード (C++26)
14+
constexpr T* operator->() const noexcept; // (3) C++26
1115
```
1216

1317
## 概要
1418
保持している有効値のメンバにアクセスする。
1519

20+
- (1) : `optional<T>`のconst版。`const T*`を返す
21+
- (2) : `optional<T>`の非const版。`T*`を返す
22+
- (3) : `optional<T&>`の場合。`T*`を返す
23+
24+
`optional<T>`では (1), (2) が定義され、`optional<T&>`では (3) のみが定義される。
25+
1626

1727
## 堅牢化された事前条件
1828
`*this`が有効な値を保持していること
1929

2030

2131
## 戻り値
22-
保持している有効値へのポインタを返す。
32+
- (1) : 有効値への`const T*`
33+
- (2) : 有効値への`T*`
34+
- (3) : 参照先への`T*`
2335

2436

2537
## 例外
@@ -72,3 +84,5 @@ int main()
7284
- [LWG Issue 2740. `constexpr optional<T>::operator->`](https://wg21.cmeerw.net/lwg/issue2740)
7385
- [P3471R4 Standard library hardening](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3471r4.html)
7486
- [P3878R1 Standard library hardening should not use the 'observe' semantic](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3878r1.html)
87+
- [P2988R12 `std::optional<T&>`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2988r12.pdf)
88+
- C++26で参照型`T&`に対する部分特殊化を追加

reference/optional/optional/op_assign.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ template <class U>
2929
optional& operator=(optional<U>&& rhs); // (6) C++17
3030
template <class U>
3131
constexpr optional& operator=(optional<U>&& rhs); // (6) C++23
32+
33+
// optional<T&>固有のオーバーロード (C++26)
34+
constexpr optional& operator=(const optional&) noexcept = default; // (7) C++26
3235
```
3336
* nullopt_t[link /reference/optional/nullopt_t.md]
3437
@@ -39,14 +42,17 @@ constexpr optional& operator=(optional<U>&& rhs); // (6) C++23
3942
- (4) : 要素型`T`に変換可能な値をムーブ代入
4043
- (5) : `optional<T>`に変換可能な`optional`オブジェクトをコピー代入
4144
- (6) : `optional<T>`に変換可能な`optional`オブジェクトをムーブ代入
45+
- (7) : `optional<T&>`のコピー代入。参照先の再束縛 (rebind) を行う (`noexcept = default`)
46+
47+
`optional<T>`では (1)~(6) が定義される。`optional<T&>`では (1), (7) が定義される。
4248
4349
4450
## テンプレートパラメータ制約
4551
- (4), (5), (6) : 型`U`が型`T`に変換可能であること
4652
4753
4854
## 効果
49-
いずれのオーバーロードでも、`*this` と `rhs` が有効な値を持っているか否かによって以下のような挙動となる。
55+
(1)~(6) では、`*this` と `rhs` が有効な値を持っているか否かによって以下のような挙動となる。
5056
5157
| | `*this` が有効な値を持っている | `*this` が有効な値を持っていない |
5258
|------------------------------------|-----------------------------------------------------------------------|----------------------------------------------------------------------|
@@ -61,6 +67,8 @@ constexpr optional& operator=(optional<U>&& rhs); // (6) C++23
6167
- (3), (6): [`std::move`](../../utility/move.md)`(*rhs)`
6268
- (4): [`std::forward`](../../utility/forward.md)`<U>(rhs)`
6369
70+
(7) では、`rhs`が保持する参照先ポインタをコピーする (参照先の再束縛)。
71+
6472
6573
## 戻り値
6674
`*this`
@@ -87,6 +95,11 @@ constexpr optional& operator=(optional<U>&& rhs); // (6) C++23
8795
- (2) : 型`T`が、[トリビアルにコピー構築可能](/reference/type_traits/is_trivially_copy_constructible.md)であり[トリビアルにコピー代入可能](/reference/type_traits/is_trivially_copy_assignable.md)かつ、[トリビアルに破棄可能](/reference/type_traits/is_trivially_destructible.md)である
8896
- (3) : 型`T`が、[トリビアルにムーブ構築可能](/reference/type_traits/is_trivially_move_constructible.md)であり[トリビアルにムーブ代入可能](/reference/type_traits/is_nothrow_move_assignable.md)かつ、[トリビアルに破棄可能](/reference/type_traits/is_trivially_destructible.md)である
8997
98+
## 備考
99+
- (7) : `optional<T&>`への代入は、参照先オブジェクトへの代入ではなく、参照先の再束縛 (rebind) を行う。これはポインタの代入と同じセマンティクスである
100+
- `optional<T&>`では、値の代入や異なる型の`optional`からの変換代入は提供されない。値を代入する場合は、暗黙の変換による`optional<T&>`の構築とコピー代入 (7) を通じて行われる
101+
102+
90103
## 例
91104
```cpp example
92105
#include <cassert>
@@ -180,3 +193,5 @@ int main()
180193
- [LWG Issue 2756. `optional<T>` should `forward` `T`'s implicit conversions](https://wg21.cmeerw.net/lwg/issue2756)
181194
- [P0602R4 `variant` and `optional` should propagate copy/move triviality](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r4.html)
182195
- [P2231R1 Missing `constexpr` in `std::optional` and `std::variant`](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2231r1.html)
196+
- [P2988R12 `std::optional<T&>`](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2988r12.pdf)
197+
- C++26で参照型`T&`に対する部分特殊化を追加

0 commit comments

Comments
 (0)