【发布时间】:2018-10-31 13:35:51
【问题描述】:
我正在尝试创建一个静态容器,它具有基于堆栈的内存并且可以容纳 T 的 N 个实例。非常相似 std::vector 我希望当前未使用的内存不包含 T 的初始化项。这通常可以通过放置 new 但这不可能在 constexpr 中使用。
使用联合 我发现了一个技巧,您可以为此使用联合,如下所示:
template <typename value_type>
union container_storage_type
{
struct empty{};
constexpr container_storage_type(): uninitialized{}{}
constexpr container_storage_type(value_type v): value(v){}
constexpr void set(value_type v)
{
*this = literal_container_storage_type{v};
}
empty uninitialized;
value_type value;
};
这使您可以通过设置 empty 成员来存储未初始化的项目,这可以解决 constexpr 中的所有成员都必须初始化的限制。
现在这种方法的问题是,如果value_type是实现operator=的类型,rule for unions says:
如果联合包含具有非平凡特殊成员函数(复制/移动构造函数、复制/移动赋值或析构函数)的非静态数据成员,则该函数默认在联合中被删除并需要定义由程序员明确表示。
这意味着为了能够使用这个技巧,我也需要在联合中实现operator=,但是看起来怎么样?
constexpr container_storage_type& operator=(const container_storage_type& other)
{
value = other.value; //ATTEMPT #1
//*this = container_storage_type(other.value);ATTEMPT #2
return *this;
}
尝试#1:这似乎不可能,因为编译器抱怨在常量表达式中根本不允许更改联合的活动成员。
尝试 #2:这适用于之前 sn-p 的 set() 方法,因为它本身不会更改活动成员,但会重新分配整个联合。然而,这个技巧似乎无法在赋值运算符中使用,因为这会导致无限递归......
我在这里遗漏了什么吗,或者这真的是在 constexpr 中使用联合作为新布局替代方案的死胡同吗?
除了我完全错过的新展示位置之外,还有其他替代方法吗?
https://godbolt.org/z/km0nTY 说明问题的代码
【问题讨论】:
-
为什么
std::array不足以满足您的用例? -
我的用例是实现一个
static_vector<T, 10>,其中 10 是容量,并且向量本身会跟踪当前的条目数。std::array单独无法留下一些条目,而T的构造函数未运行。 -
std::array<optional<T>, 10>? -
@Jarod42 我尝试了使我的
static_vector成为std::array<std::optional<T>, 10>的包装器以及计数的方法,但std::optional仅部分启用了constexpr。例如,operator=或.emplace或任何其他设置非初始化值的方式不是 constexpr -
@Tobias AFAIK,在成员不重要的情况下更改工会的活动成员的唯一方法是使用新位置。原因是需要在该存储上调用构造函数来启动它的生命周期,如果没有placement new 表达式,您将无法做到这一点。