optional
from a constexpr
function? I'm interested in both boost::optional
and std::optional
. Do they behave the same?
Unlike const , constexpr can also be applied to functions and class constructors. constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time.
optional is required to not use dynamic allocation. If an optional contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place.
std::optional contains the object within itself, depending on where it is stored (stack/data/heap) std::optional makes a copy of the contained object. Monadic functions will be added in C++23 to improve the abstraction in our code by removing the needs of writing boilerplate code.
What's more, std::optional doesn't need to allocate any memory on the free store. std::optional is a part of C++ vocabulary types along with std::any , std::variant and std::string_view .
boost::optional
cannot be returned by a constexpr
function. Or at least, the documentation provides no guarantees of this.
However, std::optional
, as defined by the accepted C++14 proposal, can be returned by a constexpr
function. But only if the type argument of the optional
is trivially destructible.
This allows the destructor of std::optional
to be trivial in those cases. At which point, there's no difficulty in destroying the object, so there's nothing stopping std::optional
from being a literal type.
The proposal is quite clear on this. If T
is trivially destructible, then most of the constructors of optional
will be constexpr
, and optional<T>
will be a literal type. And therefore, it can be created in a constexpr
function.
Boost.Optional does not support constexpr
, mainly because it was written before C++11 was released.
The current proposal for std::optional
does support constexpr
, as long as the value type T
is trivially destructible. It works because constexpr
constructors are allowed for unions (7.1.5p4); the compiler tracks which union member is initialized, ensuring that the undefined behaviour of accessing the value of a disengaged optional is caught at compile time:
struct dummy_t {};
template <class T>
union optional_storage {
static_assert( is_trivially_destructible<T>::value, "" );
dummy_t dummy_;
T value_;
constexpr optional_storage(): dummy_{} {} // disengaged
constexpr optional_storage(T const& v): value_{v} {} // engaged
~optional_storage() = default;
};
The value type must be trivially destructible because constexpr
is only useful with literal types, which must themselves have a trivial destructor.
For example, writing:
constexpr optional_storage<int> o{};
constexpr int i = o.value_;
gcc gives the error:
error: accessing ‘optional_storage<int>::value_’ member instead of initialized
‘optional_storage<int>::dummy_’ member in constant expression
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With