最終更新:2026-10-12
C++17 optional_ref¶
本稿は foonathan のブログ optional_ref discussion の紹介です。原文は、std::optional<T&>(optional 参照)がなぜ最終的に標準に入らなかったのかについての、最も優れた議論です。この問題は C++26 を目前にして再び議論されたので、核心的な論点を整理する価値があります。
1.問題:std::optional はなぜコンパイルできないのか?¶
std::optional<int>、std::optional<std::string> はどちらも問題ありませんが、std::optional<int&> はいきなりコンパイルエラーになります。原因は少し「歴史的なしこり」です:標準策定の際にその**代入セマンティクス**で合意に至らず、そこで標準には、T が参照型のときの挙動は未定義であると明記されることになりました。
では「空かもしれない参照」に何がそんなに難しいのでしょうか? 著者は 4 つの問題に整理しました:
(1)optional<T&> とポインタは同じものなのか?
(2)私たちに本当に optional<T&> は必要なのか?
(3)代入時には rebind(新しいオブジェクトに再束縛)すべきか、assign-through(指す先のオブジェクトに書き込む)すべきか?
(4)そもそも代入演算子を持つべきなのか?
著者の tl;dr な答え:違う、必要ない、rebind、持つべきでない。では理由を見ていきます。
2.optional 参照はポインタではない¶
直観には「空かもしれない参照」はポインタそのものですが、著者はより本質的な違いを指摘しています:
T&の生成とアクセスはどちらも**暗黙**:参照を手に入れたらそのまま使え、間接参照は不要;T*の生成とアクセスはどちらも**明示**:&xでアドレスを取り、*pで間接参照する必要がある。
この明示性の違いには価値があります:ポインタは「ここは null かもしれない、エイリアシングの問題があるかもしれない」と思い出させてくれます。optional<T&> を、どこでも暗黙変換される「より便利なポインタ」にしてしまうと、まさにこの保護を失ってしまいます。著者の結論:「空かもしれない」を表したいなら、明示的な T* のほうがむしろより良いドキュメントになる。
3.rebind か assign-through か¶
これが議論全体の核心的な膠着点です:
2 つの解釈があります:
- rebind:opt は今や b に束縛される(参照のエイリアスセマンティクス。
int& ra = a; ra = b;は b を a に代入する……おや、int&の代入はまさに assign-through だ!) - assign-through:b の値を a に書き込む(普通の参照
T&のセマンティクス)。
矛盾はここにあります:optional 参照が T& のセマンティクスに揃えるなら、代入は assign-through であるべきです;しかし**可変な optional**(別のオブジェクトを再び入れられるもの)は、直観上 rebind を要求します。どちらのセマンティクスも理にかなっていて、委員会は結論を出せず、こうして optional<T&> は合法化されないままです。
実践で rebind セマンティクスが欲しい場合、コミュニティの解は自分で optional_ref<T> を作ることです:内部に T* を持ち、代入はポインタの差し替え、セマンティクスは明瞭きわまりません。C++26 の std::optional_ref 提案も同じ道を歩んでいます。
4.まとめ¶
(1)optional<T&> はポインタの構文糖ではなく、両者は明示性において本質的な役割分担があります;
(2)足かせとなったのは代入セマンティクスの二義性です:rebind も assign-through も筋が通る;
(3)「null 許容な参照」が必要なとき、明示的なポインタや optional_ref は「合法化された optional
最後に思考題を一つ:optional<T&> の value() と *opt は T& を返すべきか、const T& を返すべきか? const でキャプチャされるセマンティクスも表したいなら、テンプレートパラメータはどう設計すべきでしょうか?
関連トピック¶
- C++17 [[nodiscard]] 属性 | C++那些事
- C++17 std::string_view | C++那些事
- C++17 PMR メモリリソース | C++那些事
- C++17 17の高度な機能 | C++那些事
- C++17 クラステンプレートのテンプレート引数推論 CTAD | C++那些事
- C++17 std::variant | C++那些事
- C++17 構造化束縛 | C++那些事
- C++17 テンプレート auto 推論 | C++那些事
- C++17 変数テンプレート | C++那些事