【发布时间】:2018-11-26 21:15:14
【问题描述】:
我经常使用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;
};
【问题讨论】:
-
我认为这不合法。 AFAIK 类型
std::aligned_storage<sizeof(Types),alignof(Types)>::type...的大小可以大于Types...,这会给你不对齐的访问权限。 -
as_tuple对我来说似乎是未定义的行为。您可能希望将此标记为language-lawyer。 -
当然无效。您不能将
std::tuple<X>与std::tuple<Y>别名。 -
@NathanOliver 它们只是完全不相关的类型,所以首先,这是一个严格的别名违规。但即使不考虑这一点,标准中也没有任何内容表明
std::tuple<X>可能与std::tuple<Z>有任何兼容的布局。 -
您无法访问从未创建过的对象。创建元素是不够的。考虑到您的代码,您不需要太多帮助。您最好将每个元素包装在
union unitialized{ element_type value; char c='\0';uninitialized()=default;....~unitialized(){}}中,并使您 uninitialized_tuple a... tuple => 实现 get,并专门化 tuple_size 和 tuple_element。
标签: c++ c++14 lazy-initialization stdtuple