The Merits of optional<T const&>
- Home
- Career
- Developer blog
- The Merits of optional<T const&>
3 min read
Passing function parameters by const& is very common:
void foo(T const& t);
Now, what do we do if such a parameter is optional?
std::optional<T> does not allow T to be a reference. We could use
void foo(std::optional<T> const& ot);
but this defies the purpose of passing by const&: if we want to pass a T, we would need to first copy it into an std::optional<T>, but we pass by const& precisely to avoid copying.
C++ implements references as pointers, and pointers, unlike references, can be null. They also have the same syntax as std::optional: contextual conversion to bool checks for null, and operator* accesses the value. Of course, pointers were there first, so really, std::optional got its syntax from pointers.
So why not use pointers?
void foo(T const* pt);
This compiles to the right code, but is somewhat inconvenient to use. Instead of
foo(t);
one must write
foo(&t);
or, if afraid of operator& being overloaded, even
foo(std::addressof(t));
If t is an rvalue, it gets even worse because C++ does not allow taking the address of an rvalue:
foo(std::addressof(static_cast<T&>(make_t())));
It does the right thing, but is not how we want to program.
Also, once inside foo, you can do operations on pointers that you should not be able to do:
void foo(T const* pt) {
… pt[1] … // this compiles :-(
}
So why doesn't the standard allow optional references?
void foo(std::optional<T const&> ot)
The reason is that the C++ committee could not agree on what would happen when assigning the contained type:
std::optional<T const&> ot(…);
T t=…;
ot = t; // what does this do?
Does this rebind ot to now point to t, or is this equivalent to *ot=t, changing the referenced value, under the precondition that ot is not std::nullopt?
However, for many use cases, rebinding isn't needed. Actual references also cannot be rebound. And assigning to the contained value can be achieved by *ot=t, which may be the clearer syntax anyway.
So we can postpone the discussion to another day by not supporting assignment to optional<T&> at all. optional<T&> is still very useful to pass and return optional reference parameters. The think-cell library allows references for its tc::optional. tc::optional differs from std::optional in another way, which we will talk about next time.
Do you have feedback? Send us a message at devblog@think-cell.com
- No scheduled meetings
- Time to write quality code
- International team of brilliant minds