6

While implementing std::experimental::optional (cppreference.com) I got confused by the specification of a specific constructor, namely:

constexpr optional( const T& value ); // (4)

(Source)

This constructor allows optional<T>, for a trivially destructible type T, to be constructed in constexpr context. While the first requirement, namely switching off the user-provided destructor in this case to make optional<T> a literal type, is straight forward to solve, I do not know how to get around the limitation of placement-new not being allowed in constexpr.

I thought I was supposed to implement optional<T> using std::aligned_storage<T> to allow types T that are not default constructible and satisfy any alignment requirements, if applicable. But as I said, constexpr forbids me from using placement new in that particular constructor.

Did I have to much coffee and am not seeing an obvious solution here?

Thank you

nshct
  • 1,197
  • 9
  • 29
  • Possible duplicate of [How should one use std::optional?](http://stackoverflow.com/questions/16860960/how-should-one-use-stdoptional) – Matriac Mar 08 '16 at 06:20
  • 2
    @Matriac this is a question about the implementation side. – nshct Mar 08 '16 at 06:21
  • 1
    A `union` might work for this particular constructor, but I'm not confident it will be enough to handle all cases. –  Mar 08 '16 at 07:04
  • @hvd I am currently using tag dispatching to replace the placement new with an assignment in the case that `T` is trivially destructible. But I am not sure I will run into problems with classes containing things like `std::unique_ptr` (which would result in the class being trivially destructible) that will try to delete a garbage pointer once I assign to the buffer containing garbage. – nshct Mar 08 '16 at 07:07
  • 1
    libc++ uses a `union` for their implementation; https://llvm.org/svn/llvm-project/libcxx/trunk/include/experimental/optional. So does gcc libstdc++; https://gnu.googlesource.com/gcc/+/gcc-5_3_0-release/libstdc++-v3/include/experimental/optional – Niall Mar 08 '16 at 07:28
  • Look at [this great articles](https://akrzemi1.wordpress.com/?s=optional). – Tomilov Anatoliy Mar 08 '16 at 16:49

1 Answers1

5

I do not know how to get around the limitation of placement-new not being allowed in constexpr.

That is a correct diagnostic, literal types, constexpr and new expressions don’t mix. The most straightforward way to fulfil the various requirements of std::experimental::optional<T> is to implement it with variant members. Put plainly, a union has to be involved at some point. A quick sketch:

template<typename Val>
struct optional {
    union {
        Val optional_value;
        unsigned char dummy_byte;
    };
    bool filled;

    // post-condition: no-value state
    constexpr optional()
        : dummy_byte {}
        , filled(false)
    {}

    // post-condition: has-value state
    constexpr optional(Val const& val)
        : optional_value(val)
        , filled(true)
    {}

    // other special members omitted for brevity
};

Live On Coliru

As a matter of fact, the old series of optional proposals used to have a paragraph on the technique to demonstrate that the requirements it put forth were reasonable at all. (Nowadays std::experimental::optional lives on in the various Library Fundamentals candidate TSs.)

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • Thank you. I don't know why I was so focused on aligned_storage, but this is the correct solution. – nshct Mar 08 '16 at 07:52