I'm very confused about how std::optional
's copy constructor is supposed to be implemented to meet the requirements of being constexpr
.
Note there are many other questions on Stackoverflow asking something similar, such as:
How to implement std::optional's copy constructor?
std::optional implemented as union vs char[]/aligned_storage
However, neither of these questions are actually asking about the COPY CONSTRUCTOR. I am specifically asking about the copy constructor, with a function signature (from https://en.cppreference.com/w/cpp/utility/optional/optional) as follows:
constexpr optional( const optional& other );
Now, I've read enough about std::optional
to know the basics. A typical mistake implementors make is to try and implement it with std::aligned_storage
. Since placement new cannot work in a constexpr
(at least in C++17), this won't work. Instead, a union type needs to be used so it can be directly constructed. Something like:
struct dummy_type {};
union optional_impl
{
dummy_type m_dummy;
T m_value;
};
Okay, but still... I still don't see how we are supposed to meet the requirements of implementing the copy constructor as constexpr
. The problem is that in the copy constructor, we need to check if other.has_value()
is true. If it is, we want to directly copy *other
, otherwise we just want to initialize m_dummy
. But how can we express this conditional decision in a constexpr
copy constructor?
constexpr optional( const optional& other ) : m_dummy{}
{
if (other.has_value()) new (&m_value) T(*other); // Wrong! Can't use placement new
}
The only way I can see this working is using placement new.
So I checked some actual implemenations, like the gcc implementation here:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/optional#L248
And indeed... they just use placement new. And in fact, the copy constructor isn't event constexpr
(which I guess is a defect).
Here's another implementation:
https://github.com/akrzemi1/Optional/blob/master/optional.hpp#L416
And again, they just use placement new.
So how can optional(const optional&)
ever be implemented as a constexpr
? Is this a defect in the standard or something?