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和类型之间的转换或者说“识别”。
