延迟初始化std :: tuple元素

时间:2018-11-26 21:15:14

标签: c++ c++14 lazy-initialization stdtuple

我经常使用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;
};

1 个答案:

答案 0 :(得分:2)

访问as_tuple()返回的内容是未定义的行为,因为它违反了类型别名规则。请参阅https://en.cppreference.com/w/cpp/language/reinterpret_cast

  

每当尝试通过AliasedType类型的glvalue读取或修改DynamicType类型的对象的存储值时,除非满足以下条件之一,否则行为是不确定的:

     
      
  • AliasedType和DynamicType相似。

  •   
  • AliasedType是DynamicType的(可能是cv限定的)带符号或无符号的变体。

  •   
  • AliasedType是std :: byte,(从C ++ 17开始)char或unsigned char:这允许将任何对象的对象表示形式检查为字节数组。

  •