【发布时间】:2017-01-10 18:57:36
【问题描述】:
我的目标是写std::variant,可能还不够成熟,但至少有完整的构造函数/析构函数对和std::get<>() 函数。
我尝试使用 char 数组保留内存。它的大小由使用find_biggest_size<>()函数找到的最大类型决定。构造函数使用静态断言,因为它执行检查类型是否在指定类型列表中。目前,构造函数和就地构造函数都可以工作。
template <typename ... alternatives>
class variant
{
char object[find_biggest_size<alternatives...>::value];
public:
template <typename T>
variant(T&& other)
{
static_assert(is_present<T, alternatives...>::value, "type is not in range");
new ((T*)&object[0]) T(std::forward<T>(other));
}
template <typename T, typename ... ArgTypes>
variant(in_place_t<T>, ArgTypes&& ... args)
{
static_assert(is_present<T, alternatives...>::value, "type is not in range");
new ((T*)&object[0]) T(std::forward<ArgTypes>(args)...);
}
~variant()
{
// what to do here?
}
};
然后我偶然发现了一个问题。我不知道当对象死亡时要执行什么析构函数。最重要的是,无法访问底层对象,因为我无法专门化 std::get<>() 来获得正确的类型。
我的问题是:对象创建后如何存储类型?这是正确的方法吗?如果没有,我应该使用什么?
编辑:
我尝试应用 cmets。问题是当前活动的类型的索引不能是constexpr,因此我无法从类型列表中提取所需的类型并调用适当的析构函数。
~variant()
{
using T = typename extract<index, alternatives...>::type;
(T*)&object[0]->~T();
}
编辑:
我已经做了一个基线实现。它可以工作,但有很多缺失的功能。你可以找到它here。我很高兴收到评论,但请先阅读how do I write a good answer?。
【问题讨论】:
-
一个变体会跟踪其中存在的对象的类型。例如。通过index。
-
@OlzhasZhumabek:“这不是我写的只是花哨的对齐方式吗?”不,因为你没有将它对齐到所有对齐的最大对齐的类型。 “问题是我不能让它成为 constexpr” 你必须以一种不需要它是
constexpr的方式来编写它。毕竟,类型不能是一个常量表达式,因为variant的重点在于它存储的类型是在运行时确定的。 -
@NicolBolas,伙计,你说的我明白了。虽然我还需要一些碎片。当我将它们全部收集起来时,我会发布实现。
-
不久前,我们对 C++ UG 中变体的棘手部分进行了一次闪电般的讨论。以下是幻灯片:slideshare.net/ComicSansMS/…
标签: c++ templates variant c++17