Blog
网站首页
C++中variant以及visit实现原理
C++中variant以及visit实现原理
2023-03-28 10:51
2023-03-28 10:55
作者:
xmh0511
提交
````cpp #include
#include
#include
#include
template
struct Indice{}; template
union Storage{}; template
union Storage
{ template
Storage(U u, Indice
):Storage(u,Indice
{}){ } template
Storage(U u,Indice<0>):ele(u){ } First ele; Storage
rest; }; template
struct Variant{ template
Variant(U u, Indice
i):storage(u,i),Index(N){} Storage
storage; std::size_t Index; }; template
auto get_index_element(Storage
v, Indice
){ static_assert(sizeof...(T) > N); return get_index_element(v.rest,Indice
{}); } template
auto get_index_element(Storage
v, Indice<0>){ return v.ele; } template
auto dispatch(F f, V v){ return f(get_index_element(v,Indice
{})); } template
auto convert_to_array(std::index_sequence
){ using type = decltype(dispatch<0,F,S>); return std::array
{ dispatch
... }; } template
auto convert_to_array(){ return convert_to_array
>(std::make_index_sequence
()); } template
auto visit(F f, Variant
v){ auto arr = convert_to_array
(); return arr[v.Index](f,v.storage); } int main() { auto c = Variant
{1,Indice<0>{}}; visit([](auto v){ std::cout<< typeid(v).name(); },c); } ```` visit的主体思想是通过模板函数的模板参数记录`std::size_t`类型的常量,为每个层级的元素的存储生成一个访问函数,该函数最终的函数类型就是一个参数类型为(访问函数类型,Variant),返回类型为访问函数返回类型的一个接口函数,常量的类型被类型擦除了因为不属于函数类型。`convert_to_array`就是将对`Storage`的访问转化成数组,比如`Storage
`可以转换对`Storage
`和`Storage
`访问的数组, 对应的常量访问就是`0`, `1`记录到`dispatch`的模板参数中,`get_index_element`可以通过记录的模板参数常量值来递归出需要访问的最终Storage的成员数据 > 0 => `Storage
::ele` > 1 => `Storage
:: rest :: ele` `dispatch<0>, dispatch<1>`实例化后的函数类型就是一个公共类型 `ReturnType(F, Storage
)`,这样一个公共类型就可以通过数组存储,数组的元素就可以通过非编译期的下标值来访问。 https://godbolt.org/z/4YxbxKffd