Last updated:2026-10-12
C++17 optional_ref¶
This post retells foonathan's blog optional_ref discussion; the original is the single best discussion of why std::optional<T&> (an optional reference) never made it into the standard. The topic was dug up again right before C++26, so it is worth walking through the core arguments.
1. The Problem: Why Doesn't std::optional Compile?¶
std::optional<int>, std::optional<std::string> are both fine, but std::optional<int&> fails to compile outright. The reason is a bit of "historical baggage": when the standard was drawn up, no consensus was reached on its assignment semantics, so the standard simply states that behavior is undefined when T is a reference type.
So what is so hard about a "possibly empty reference"? The author distilled four questions:
(1) Is optional<T&> the same thing as a pointer?
(2) Do we really need optional<T&>?
(3) On assignment, should it rebind (rebind to the new object) or assign-through (write to the referred object)?
(4) Should it even have an assignment operator at all?
The author's tl;dr answers: no, we do not, rebind, and it should not. Let us see why.
2. An optional Reference Is Not a Pointer¶
Intuitively, a "possibly empty reference" is just a pointer, but the author points out a more essential difference:
- creation of and access to a
T&are both implicit: once you have the reference you just use it, no dereference needed; - creation of and access to a
T*are both explicit: you need&xto take the address and*pto dereference.
This explicitness difference has value: a pointer reminds you "this may be null, there may be aliasing problems here". Making optional<T&> an "easier pointer" with implicit conversions everywhere throws away exactly this layer of protection. The author's conclusion: if you want to express "may be empty", an explicit T* is actually better documentation.
3. rebind or assign-through¶
This is the core deadlock of the whole discussion:
Two readings:
- rebind: opt now binds to b (the alias semantics of references —
int& ra = a; ra = b;assigns b to a... wait, assignment ofint&is precisely assign-through!) - assign-through: write b's value into a (the semantics of an ordinary reference
T&).
Here lies the contradiction: if an optional reference wants to align with the semantics of T&, assignment should be assign-through; yet a mutable optional (one that can be re-filled with another object) intuitively demands rebind. Both semantics are reasonable, the committee could not settle it, and so optional<T&> was never legalized.
In practice, when you want rebind semantics, the community's solution is to roll your own optional_ref<T>: internally it stores a T*, and assignment just swaps the pointer — semantics crystal clear. The C++26 std::optional_ref proposal follows the same route.
4. Summary¶
(1) optional<T&> is not syntactic sugar for a pointer; the two have an essential division of labor in explicitness;
(2) what blocked it is the ambiguity of assignment semantics: both rebind and assign-through make sense;
(3) when you need a "nullable reference", an explicit pointer or an optional_ref is a safer choice than a "legalized optional
Finally, a question to ponder: should optional<T&>'s value() and *opt return T& or const T&? And if you also want to express captured-as-const semantics, how should the template parameter be designed?
Related Topics¶
- C++17 [[nodiscard]] Attribute | C++那些事
- C++17 std::string_view | C++那些事
- C++17 PMR Memory Resources | C++那些事
- C++17 Seventeen Advanced Features | C++那些事
- C++17 Class Template Argument Deduction CTAD | C++那些事
- C++17 std::variant | C++那些事
- C++17 Structured Bindings | C++那些事
- C++17 Template auto Deduction | C++那些事
- C++17 Variable Templates | C++那些事