在实现类似std :: variant的类时存储类型标记的麻烦

Inc*_*ble 14 c++ templates variant c++17

我的目标是写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?
    }
};
Run Code Online (Sandbox Code Playgroud)

然后我偶然发现了一个问题.我不知道当对象死亡时要执行什么析构函数.最重要的是,不可能访问底层对象,因为我无法专门std::get<>()获得正确的类型.

我的问题是:如何在创建对象后存储类型?这是正确的方法吗?如果没有,我应该使用什么?

编辑:

我试图应用评论.问题是当前存活的类型的索引不能constexpr,因此我无法从类型列表中提取所需的类型并调用适当的析构函数.

~variant()
{
    using T = typename extract<index, alternatives...>::type;
    (T*)&object[0]->~T();
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我做了一个基线实现.它有效,但有很多缺少的功能.你可以在这里找到它.我很乐意收到评论,但请先阅读如何写出一个好的答案?.

Ric*_*ges 11

我怎么可能开始:

#include <iostream>
#include <utility>
#include <array>

template<class...Types>
struct variant
{
    variant() {}
    ~variant()
    {
        if (type_ >= 0)
        {
            invoke_destructor(type_, reinterpret_cast<char*>(std::addressof(storage_)));
        }
    }

    template<class T> static void invoke_destructor_impl(char* object)
    {
        auto pt = reinterpret_cast<T*>(object);
        pt->~T();
    }

    static void invoke_destructor(int type, char* address)
    {
        static const std::array<void (*)(char*), sizeof...(Types)> destructors
        {
            std::addressof(invoke_destructor_impl<Types>)...
        };
        destructors[type](address);
    }

    std::aligned_union_t<0, Types...> storage_;
    int type_ = -1;

};

int main()
{
    variant<int, std::string> v;

}
Run Code Online (Sandbox Code Playgroud)