Reputation: 7415
optional
from a constexpr
function? I'm interested in both boost::optional
and std::optional
. Do they behave the same?
Upvotes: 11
Views: 1337
Reputation: 157344
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
Upvotes: 6
Reputation: 473352
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.
Upvotes: 11