The Merits of optional<T const&>

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 !

Sign up for blog updates

Don't miss out on new posts! Sign up to receive a notification whenever we publish a new article.

Just submit your email address below. Be assured that we will not forward your email address to any third party.

Please refer to our privacy policy on how we protect your personal data.

Share