Ленивая инициализация элементов std :: tuple

Я часто использую std::aligned_storage указать неинициализированный член класса. Типичным примером является static_vector, который хранит свои элементы в структуре.

Тем не менее, я не совсем уверен, что я должен делать, когда я хочу std::tuple быть созданным шаг за шагом, инициализация его членов в неуказанном порядке в разные моменты времени.

Было бы законно создать

std::tuple< std::aligned_storage<sizeof(Types),alignof(Types)>::type...>

а затем заново интерпретировать ссылку на член как std::tuple<Types...>&?

Например:

#include <bitset>
#include <memory>
#include <new>
#include <tuple>
#include <utility>

template < class... Ts >
class uninitialized_tuple {
public:
using tuple_type   = typename std::tuple<Ts...>;
using buffer_type =
std::tuple<
typename std::aligned_storage<sizeof(Ts),alignof(Ts)>::type...
>;

~uninitialized_tuple() {
destruct_helper<std::index_sequence_for<Ts...>>::erase(*this);
}

tuple_type& as_tuple() {
reinterpret_cast<tuple_type&>(_storage);
}

bool valid() const {
return _is_set.all();
}

template < size_t index, class... Args >
void emplace( Args&&... args ) {
using element_type = typename std::tuple_element<index,tuple_type>::type;
new (&std::get<index>(_storage)) element_type( std::forward<Args>(args)...);
_is_set.set(index);
}

template < size_t index >
void erase() {
using element_type = typename std::tuple_element<index,tuple_type>::type;
if( _is_set[index] ) {
std::get<index>(_storage).~element_type();
_is_set.reset(index);
}
}

private:
template < class Seq >
struct destruct_helper {
static void erase( uninitialized_tuple& ) {}
};

template < size_t index, size_t... indices >
struct destruct_helper<std::index_sequence<index,indices...>> {
static void erase( uninitialized_tuple& value ) {
value.erase<index>();
destruct_helper<std::index_sequence<indices...>>::erase_one(value);
}
};

buffer_type                _storage;
std::bitset<sizeof...(Ts)> _is_set;
};

0

Решение

Доступ к тому, что возвращается as_tuple() является неопределенное поведение как это нарушает правила псевдонимов типов. Пожалуйста, обратитесь к https://en.cppreference.com/w/cpp/language/reinterpret_cast:

Всякий раз, когда делается попытка прочитать или изменить сохраненное значение объекта типа DynamicType с помощью glvalue типа AliasedType, поведение не определено, если не выполнено одно из следующих условий:

  • AliasedType и DynamicType похожи.

  • AliasedType является (возможно, cv-квалифицированным) подписанным или неподписанным вариантом DynamicType.

  • AliasedType имеет тип std :: byte, (начиная с C ++ 17) char или unsigned char: это позволяет исследовать объектное представление любого объекта в виде массива байтов.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]