Ever since std::optional appeared in C++, it was embraced by programmers with functional background but is still a subject of frequent debates. This article will not attempt to contribute to these debates, although I have to admit that library APIs that use std::optional for return types of functions that may not have a result, feels natural to me coming from Haskell world.
Its implicit constructors make it particularly easy to return values of contained types without any boilerplate. Here is an example from cppreference
What’s not to like about this? Well, let’s take another example
and the assembly it generates
Clang is using a jump table to efficiently dispatch each switch branch to appropriate label. There are no surprises for DEFAULT and NULLOPT branches - we simply mark returned optional as empty
and in IMPLICIT branch we call provide and move its value into returned optional
What may come as a surprise though is the difference between IMPLICIT_MOVE version which is using a move constructor
unlike INPLACE branch that returns optional with Foo’s value as instructed by its constructor
In this particular example the difference is just a value of the moved type, but for more complex types the difference between inplace initialization and initialization + move can come at a significant cost.
What’s the moral? I’d argue that having an implicit constructor that silently accepts rvalues is somewhat unfortunate, as most clients never find out that there is a more efficient in-place way to initialize their optionals.