gnzlbg
gnzlbg

Reputation: 7415

Can I return an optional from a constexpr function?

I'm interested in both boost::optional and std::optional. Do they behave the same?

Upvotes: 11

Views: 1337

Answers (2)

ecatmur
ecatmur

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

Nicol Bolas
Nicol Bolas

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

Related Questions