Доброго времени суток!
Нужна консультация от людей, которые знают формальную часть C++ лучше меня.
Делаю самодельный аналог union/variant. Что-то типа:
using void_ptr_t = void *;
template< typename T >
struct my_union_t
{
alignas( std::max( alignof(T), alignof(void_ptr_t) ) )
std::array< std::byte, std::max( sizeof(T), sizeof(void_ptr_t) ) > _content;
};
Т.е. это такое специализированное хранилище, в котором может быть либо экземпляр типа T, либо же указатель.
Либо вообще может ничего не быть, но это к делу не относится.
Важно то, что в качестве T может быть нетривиальный тип со своими конструкторами и деструктором. Вроде std::string или std::vector.
Когда мне нужно поместить в my_union_t::_content значение типа T, то естественным образом используется placement new:
template< typename T >
void
store_to( my_union_t<T> & dest, T value )
{
new( dest._content.data() ) T{ std::move(value) };
}
Но вот нужен ли с формальной точки зрения placement new когда мне требуется туда сохранить значение указателя?
Т.е. должен ли я писать так:
template< typename T >
void
store_to( my_union_t<T> & dest, void_ptr_t value )
{
new( dest._content.data() ) void_ptr_t{ value };
}
или же вполне достаточно и reinterpret_cast:
template< typename T >
void
store_to( my_union_t<T> & dest, void_ptr_t value )
{
*(reinterpret_cast<void_ptr_t **>(dest._content.data())) = value;
}
?
Оно как бы понятно, что современные компиляторы без проблем возьмут и версию с reinterpret_cast. Но хочется понять, насколько это легально.
Сам думаю, что легальной является только версия с placement new и для T, и для void_ptr_t. Однако, не мешало бы получить какие-то подтверждения от знающих людей, чтобы быть уверенным.
PS. Вопрос о том, почему бы не взять std::variant выходит за рамки обсуждения, есть на то причины. Если брать обычный унаследованный из Си union, то для случаев, когда T является нетривиальным типом (вроде std::string) там свои заморочки, которые не делают код более понятным, скорее даже наоборот.
PPS. Про то, что для my_union_t нужны функции очистки содержимого и соответствующие процедуры для копирования/перемещения/swap я в курсе.