C语言如何从头实现一个变体类型(Variant)?

摘要:MyVariant 从零实现一个C++Variant. 本文内容参考博主双笙子佯谬 问题场景 我们知道,variant是支持存储多种不同指定类型的的容器。 比如对于一个variant&lt
MyVariant 从零实现一个C++Variant. 本文内容参考博主双笙子佯谬 问题场景 我们知道,variant是支持存储多种不同指定类型的的容器。 比如对于一个variant<int,double,std::sttring>,我们可以赋值int,double,string类型。而这些类型个数是不确定的,所以我们一定需要变参模板。 所以一个基本的框架形成了 template<typename...Ts> struct Variant{ public: template<typename T> Variant(T value){} private: ??? value; }; 这里我们的value类型是一个很尴尬的选择,可能是int,可能是std::string,而我们也不可能使用类似T value的操作。因此,我们可以选择union. union{ ???; ???; }value; 问题又来了,里面的类型怎么填?你可能会想如下类似: union{ Ts...; }value; 但是很遗憾,union不支持变参模板,直接使用union不成功。因此需要我们手动实现一个类似的union. union简而言之就是内存重叠。多个类型共用一个内存,内存大小为其中最大的那个类型大小值。 static constexpr size_t max_size() { size_t max = 0; // 使用折叠表达式(C++17) ((max = (sizeof(Ts) > max ? sizeof(Ts) : max)), ...); return max; } alignas(max_size()) char m_union[max_size()]; 这里我们每先计算出所有类型之中的最大值,然后开辟一块内存,同时内存对齐。 之所以需要创建一个max_size函数,是因为std::max在不同的编译器中实现不同,可能不支持编译器操作。 此外为了能够识别不同的类型,我们还需要添加一个标志 std::size_t m_index; 现在的结构就是这样 template<typename...Ts> struct Variant{ public: template<typename T> Variant(T value){} private: static constexpr size_t max_size() { size_t max = 0; // 使用折叠表达式(C++17) ((max = (sizeof(Ts) > max ? sizeof(Ts) : max)), ...); return max; } alignas(max_size()) char m_union[max_size()]; }; 类型的识别 我们使用m_index来作为类型标签,那么一定要有方法能够进行index和类型之间的转换或者说“识别”。
阅读全文