My aim is to write std::variant
, may be not full blown, but at least with fully working constructor/destructor pair and std::get<>()
function.
I tried to reserve a memory using char array. The size of it is determined by the biggest type, which is found by using find_biggest_size<>()
function. The constructor uses static assert, because it performs check if the type is in the list of specified types. For now, the constructor and in place constructor works.
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?
}
};
Then I've stumbled upon a problem. I don't know what destructor to execute when the object dies. On top of that, it is impossible to access the underlying object, since I can't specialize std::get<>()
to get the right type.
My question is: how to store the type after the creation of the object? Is it the right approach? If not, what should I use?
EDIT:
I tried to apply the comments. The problem is that the index of the type that is currently alive can't be constexpr
, thus I can't extract the needed type from type list and invoke appropriate destructor.
~variant()
{
using T = typename extract<index, alternatives...>::type;
(T*)&object[0]->~T();
}
EDIT:
I've made a baseline implementation. It works, but has lots of missing features. You can find it here. I would be glad to receive a review, but please first read how do I write a good answer?.
std::aligned_union
exists.constexpr
. After all, the type cannot be a constant expression, since the whole point ofvariant
is that the type it stores is determined at runtime.