Я очень озадачен тем, как конструктор копирования std::optional
должен быть реализован в соответствии с требованиями constexpr
.
Обратите внимание, что в Stackoverflow есть много других вопросов, задающих нечто подобное,например:
Как реализовать конструктор копирования std :: option?
std :: необязательно реализован как union vs char [] / align_storage
Однако ни один из этих вопросов на самом деле не задает вопрос о КОПИРОВАЛЬНОМ КОНСТРУКТОРЕ. Я специально спрашиваю о конструкторе копирования с сигнатурой функции (от https://en.cppreference.com/w/cpp/utility/optional/optional) следующим образом:
constexpr optional( const optional& other );
Теперь я прочитал достаточно о std::optional
, чтобы знатьОсновы. Типичная ошибка, которую делают разработчики, заключается в том, чтобы попытаться реализовать ее с std::aligned_storage
. Так как размещение new не может работать в constexpr
(по крайней мере, в C ++ 17), это не будет работать. Вместо этого требуется тип объединениябыть использованным, чтобы его можно было построить непосредственно. Что-то вроде:
struct dummy_type {};
union optional_impl
{
dummy_type m_dummy;
T m_value;
};
Хорошо, но все же ... Я все еще не понимаю, как мы должны отвечать требованиямреализация конструктора копирования как constexpr
. Проблема в том, что в конструкторе копирования нам нужно проверить, истинно ли other.has_value()
. Если это так, мы хотим напрямую скопировать *other
, в противном случае мы просто хотим инициализировать m_dummy
. Но как мы можем выразить это условное решение в constexpr
конструкторе копирования?
constexpr optional( const optional& other ) : m_dummy{}
{
if (other.has_value()) new (&m_value) T(*other); // Wrong! Can't use placement new
}
Единственный способ увидеть эту работу - использовать новое размещение.
Поэтому я проверил некоторыефактические реализации, такие как реализация gccздесь:
https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/optional#L248
И действительно ... они просто используют размещение новых. И фактически, конструктор копирования не является событием constexpr
(что, я думаю, является дефектом).
Вот еще одна реализация:
https://github.com/akrzemi1/Optional/blob/master/optional.hpp#L416
И снова, они просто используют размещение новых.
Так как же optional(const optional&)
может быть реализован как constexpr
? Это дефект в стандарте или что-то?