总体结构
variant
首先是variant
的结构,variant
的模板声明长这样:
1 2 3 4 5 6 7 8 9 10 11 12 template <typename ... _Types> class variant : private __detail::__variant::_Variant_base<_Types...>, private _Enable_default_constructor< __detail::__variant::_Traits<_Types...>::_S_default_ctor, variant<_Types...>>, private _Enable_copy_move< __detail::__variant::_Traits<_Types...>::_S_copy_ctor, __detail::__variant::_Traits<_Types...>::_S_copy_assign, __detail::__variant::_Traits<_Types...>::_S_move_ctor, __detail::__variant::_Traits<_Types...>::_S_move_assign, variant<_Types...>>
_Enable_copy_move
在上一篇optional解析 中解释了,这里不同之处在于要考察variant
的模板参数包内多个类型的可复制性、可移动性,如果其中某个类型不可复制或不可移动,那么variant
亦不可复制或不可移动。
_Enable_default_constructor
为用于生成默认构造的helper模板,代码长这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <bool _Switch, typename _Tag = void > struct _Enable_default_constructor { constexpr _Enable_default_constructor() noexcept = default ; constexpr _Enable_default_constructor(_Enable_default_constructor const &) noexcept = default ; constexpr _Enable_default_constructor(_Enable_default_constructor&&) noexcept = default ; _Enable_default_constructor& operator =(_Enable_default_constructor const &) noexcept = default ; _Enable_default_constructor& operator =(_Enable_default_constructor&&) noexcept = default ; constexpr explicit _Enable_default_constructor(_Enable_default_constructor_tag) { } };
当然它也有一个_Switch
为false
的特化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template <typename _Tag> struct _Enable_default_constructor <false , _Tag> { constexpr _Enable_default_constructor() noexcept = delete ; constexpr _Enable_default_constructor(_Enable_default_constructor const &) noexcept = default ; constexpr _Enable_default_constructor(_Enable_default_constructor&&) noexcept = default ; _Enable_default_constructor& operator =(_Enable_default_constructor const &) noexcept = default ; _Enable_default_constructor& operator =(_Enable_default_constructor&&) noexcept = default ; constexpr explicit _Enable_default_constructor(_Enable_default_constructor_tag) { } };
对于variant
其默认空构要求保有第一个类型的值,所以就要求第一个类型必须有默认空构:
1 2 3 4 5 6 7 8 9 10 11 template <typename ... _Types> struct _Traits { static constexpr bool _S_default_ctor = is_default_constructible_v<typename _Nth_type<0 , _Types...>::type>; } template <typename _Tp0, typename ... _Rest> struct _Nth_type <0 , _Tp0, _Rest...> { using type = _Tp0; };
_Variant_base
与其他stl模板类似,variant
的实现主要在基类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 template <typename ... _Types> struct _Variant_base : _Move_assign_alias<_Types...> { using _Base = _Move_assign_alias<_Types...>; constexpr _Variant_base() noexcept (_Traits<_Types...>::_S_nothrow_default_ctor) : _Variant_base(in_place_index<0 >) { } template <size_t _Np, typename ... _Args> constexpr explicit _Variant_base(in_place_index_t <_Np> __i, _Args&&... __args) : _Base(__i, std::forward<_Args>(__args)...) { } _Variant_base(const _Variant_base&) = default ; _Variant_base(_Variant_base&&) = default ; _Variant_base& operator =(const _Variant_base&) = default ; _Variant_base& operator =(_Variant_base&&) = default ; };
特殊成员函数套娃
这里存在几个套娃似的的结构用于解决实际存储的复制构造、移动构造、复制赋值、移动赋值问题,首先是移动赋值,_Variant_base
继承的_Move_assign_alias
相关代码:
1 2 3 4 5 6 7 8 9 10 11 template <typename ... _Types> using _Move_assign_alias = _Move_assign_base<_Traits<_Types...>::_S_trivial_move_assign, _Types...>; template <typename ... _Types> struct _Traits { static constexpr bool _S_trivial_move_assign = _S_trivial_dtor && _S_trivial_move_ctor && (is_trivially_move_assignable_v<_Types> && ...); }
_Move_assign_base
按实际参数包是否可移动赋值,分别为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 template <bool , typename ... _Types> struct _Move_assign_base : _Copy_assign_alias<_Types...> { using _Base = _Copy_assign_alias<_Types...>; using _Base::_Base; _GLIBCXX20_CONSTEXPR _Move_assign_base& operator =(_Move_assign_base&& __rhs) noexcept (_Traits<_Types...>::_S_nothrow_move_assign) { __variant::__raw_idx_visit( [this ](auto && __rhs_mem, auto __rhs_index) mutable { constexpr size_t __j = __rhs_index; if constexpr (__j != variant_npos) { if (this ->_M_index == __j) __variant::__get<__j>(*this ) = std::move (__rhs_mem); else { using _Tj = typename _Nth_type<__j, _Types...>::type; if constexpr (is_nothrow_move_constructible_v<_Tj>) __variant::__emplace<__j>(*this , std::move (__rhs_mem)); else { using _Variant = variant<_Types...>; _Variant& __self = __variant_cast<_Types...>(*this ); __self.template emplace <__j>(std::move (__rhs_mem)); } } } else this ->_M_reset(); }, __variant_cast<_Types...>(__rhs)); return *this ; } _Move_assign_base(const _Move_assign_base&) = default ; _Move_assign_base(_Move_assign_base&&) = default ; _Move_assign_base& operator =(const _Move_assign_base&) = default ; }; template <typename ... _Types> struct _Move_assign_base <true , _Types...> : _Copy_assign_alias<_Types...> { using _Base = _Copy_assign_alias<_Types...>; using _Base::_Base; };
即在参数不可移动赋值时使用自定义的赋值操作,这里先不管这些移动、复制操作,先来看看最终的存储,省略中间套娃代码来到:
_Variant_storage
1 2 3 4 5 6 7 8 9 template <typename ... _Types> using _Variant_storage_alias = _Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>; template <bool , typename ... _Types> struct _Copy_ctor_base : _Variant_storage_alias<_Types...> { }
然后又到了是否平凡析构的环节…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 template <typename ... _Types> struct _Traits { static constexpr bool _S_trivial_dtor = (is_trivially_destructible_v<_Types> && ...); } template <bool __trivially_destructible, typename ... _Types> struct _Variant_storage ; template <typename ... _Types> struct _Variant_storage <false , _Types...> { constexpr _Variant_storage() : _M_index(static_cast <__index_type>(variant_npos)) { } template <size_t _Np, typename ... _Args> constexpr _Variant_storage(in_place_index_t <_Np>, _Args&&... __args) : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), _M_index{_Np} { } constexpr void _M_reset() { if (!_M_valid()) [[unlikely]] return ; std::__do_visit<void >([](auto && __this_mem) mutable { std::_Destroy(std::__addressof(__this_mem)); }, __variant_cast<_Types...>(*this )); _M_index = static_cast <__index_type>(variant_npos); } _GLIBCXX20_CONSTEXPR ~_Variant_storage() { _M_reset(); } constexpr bool _M_valid() const noexcept { if constexpr (__variant::__never_valueless<_Types...>()) return true ; return this ->_M_index != __index_type(variant_npos); } _Variadic_union<_Types...> _M_u; using __index_type = __select_index<_Types...>; __index_type _M_index; }; template <typename ... _Types> struct _Variant_storage <true , _Types...> { constexpr _Variant_storage() : _M_index(static_cast <__index_type>(variant_npos)) { } template <size_t _Np, typename ... _Args> constexpr _Variant_storage(in_place_index_t <_Np>, _Args&&... __args) : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), _M_index{_Np} { } constexpr void _M_reset() noexcept { _M_index = static_cast <__index_type>(variant_npos); } constexpr bool _M_valid() const noexcept { if constexpr (__variant::__never_valueless<_Types...>()) return true ; return this ->_M_index != static_cast <__index_type>(variant_npos); } _Variadic_union<_Types...> _M_u; using __index_type = __select_index<_Types...>; __index_type _M_index; };
两个特化区别在于析构时的选择,但两个都包含相同的数据成员_M_u
与_M_index
,先来看这个_Variadic_union
:
_Variadic_union
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 template <typename ... _Types> union _Variadic_union { _Variadic_union() = default ; template <size_t _Np, typename ... _Args> _Variadic_union(in_place_index_t <_Np>, _Args&&...) = delete ; }; template <typename _First, typename ... _Rest> union _Variadic_union <_First, _Rest...> { constexpr _Variadic_union() : _M_rest() { } template <typename ... _Args> constexpr _Variadic_union(in_place_index_t <0 >, _Args&&... __args) : _M_first(in_place_index<0 >, std::forward<_Args>(__args)...) { } template <size_t _Np, typename ... _Args> constexpr _Variadic_union(in_place_index_t <_Np>, _Args&&... __args) : _M_rest(in_place_index<_Np-1 >, std::forward<_Args>(__args)...) { } #if __cpp_lib_variant >= 202106L _Variadic_union(const _Variadic_union&) = default ; _Variadic_union(_Variadic_union&&) = default ; _Variadic_union& operator =(const _Variadic_union&) = default ; _Variadic_union& operator =(_Variadic_union&&) = default ; ~_Variadic_union() = default ; constexpr ~_Variadic_union() requires (!__has_trivial_destructor(_First)) || (!__has_trivial_destructor(_Variadic_union<_Rest...>)) { } #endif _Uninitialized<_First> _M_first; _Variadic_union<_Rest...> _M_rest; };
这是个递归定义的template union,上面的_Variadic_union
是无类型参数时的template,下面的则是递归定义。_Uninitialized<_First> _M_first
是递归定义中这一层的实际值,_Variadic_union<_Rest...> _M_rest
递归定义剩余参数包,_M_first
与_M_rest
共享一块内存。
来看看_Uninitialized
:
_Uninitialized
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 template <typename _Type, bool = std::is_trivially_destructible_v<_Type>> struct _Uninitialized; template <typename _Type> struct _Uninitialized <_Type, true > { template <typename ... _Args> constexpr _Uninitialized(in_place_index_t <0 >, _Args&&... __args) : _M_storage(std::forward<_Args>(__args)...) { } constexpr const _Type& _M_get() const & noexcept { return _M_storage; } constexpr _Type& _M_get() & noexcept { return _M_storage; } constexpr const _Type&& _M_get() const && noexcept { return std::move (_M_storage); } constexpr _Type&& _M_get() && noexcept { return std::move (_M_storage); } _Type _M_storage; }; template <typename _Type> struct _Uninitialized <_Type, false > { #if __cpp_lib_variant >= 202106L template <typename ... _Args> constexpr _Uninitialized(in_place_index_t <0 >, _Args&&... __args) : _M_storage(std::forward<_Args>(__args)...) { } constexpr ~_Uninitialized() { } _Uninitialized(const _Uninitialized&) = default ; _Uninitialized(_Uninitialized&&) = default ; _Uninitialized& operator =(const _Uninitialized&) = default ; _Uninitialized& operator =(_Uninitialized&&) = default ; constexpr const _Type& _M_get() const & noexcept { return _M_storage; } constexpr _Type& _M_get() & noexcept { return _M_storage; } constexpr const _Type&& _M_get() const && noexcept { return std::move (_M_storage); } constexpr _Type&& _M_get() && noexcept { return std::move (_M_storage); } struct _Empty_byte { }; union { _Empty_byte _M_empty; _Type _M_storage; }; #else template <typename ... _Args> constexpr _Uninitialized(in_place_index_t <0 >, _Args&&... __args) { ::new ((void *)std::addressof (_M_storage)) _Type(std::forward<_Args>(__args)...); } const _Type& _M_get() const & noexcept { return *_M_storage._M_ptr(); } _Type& _M_get() & noexcept { return *_M_storage._M_ptr(); } const _Type&& _M_get() const && noexcept { return std::move (*_M_storage._M_ptr()); } _Type&& _M_get() && noexcept { return std::move (*_M_storage._M_ptr()); } __gnu_cxx::__aligned_membuf<_Type> _M_storage; #endif };
根据类型是否可平凡析构特化了两个版本的_Uninitialized
,可平凡析构时_Uninitialized
即是类型_Type
的简单封装;
不可平凡析构且标准为c++17时实际存储为__gnu_cxx::__aligned_membuf<_Type>
,__aligned_membuf
是gcc内常用的内存对齐缓冲,该类型内包含一个实际存储对象的字节数组,构造、析构都不操作实际对象,所以上述代码①处使用了placement new构造实际对象,当前场景的_Uninitialized
也由编译器生成平凡析构不对实际对象进行析构;
不可平凡析构且为c++20以后标准时,这里由于c++20标准后constexpr变量必须拥有constexpr析构(所谓常量析构),__aligned_membuf
不具备常量析构,所以这里另写了个分支。该场景下使用一个带有_Empty_byte
的union控制存储,并提供一个非平凡的常量析构,且这个析构并不析构内在对象,实际对象的析构由外部控制。
所以_Variadic_union
即一个可变参数union,不难猜出_Variant_storage
中的__index_type
即是表明当前union存在项的索引,这里展开下前面的using __index_type = __select_index<_Types...>
,把相关代码贴下:
__select_index
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 template <typename ... _Types> using __select_index = typename __select_int::_Select_int_base<sizeof ...(_Types), unsigned char , unsigned short >::type::value_type; template <unsigned long long _Val, typename _IntType, typename ... _Ints> struct _Select_int_base <_Val, _IntType, _Ints...> : __conditional_t <(_Val <= __gnu_cxx::__int_traits<_IntType>::__max), integral_constant<_IntType, (_IntType)_Val>, _Select_int_base<_Val, _Ints...>> { }; template <bool _Cond, typename _If, typename _Else> using __conditional_t = typename __conditional<_Cond>::template type<_If, _Else>; template <bool > struct __conditional { template <typename _Tp, typename > using type = _Tp; }; template <> struct __conditional <false > { template <typename , typename _Up> using type = _Up; }; template <typename _Tp, _Tp __v> struct integral_constant { static constexpr _Tp value = __v; typedef _Tp value_type; typedef integral_constant<_Tp, __v> type; constexpr operator value_type () const noexcept { return value; } #if __cplusplus > 201103L #define __cpp_lib_integral_constant_callable 201304L constexpr value_type operator () () const noexcept { return value; } #endif }; struct _Select_int_base <sizeof ...(_Types), unsigned char , unsigned short > : __conditional_t <(sizeof ...(_Types) <= __gnu_cxx::__int_traits<_unsigned char >::__max), integral_constant<unsigned char , (unsigned char )sizeof ...(_Types)>, _Select_int_base<sizeof ...(_Types), unsigned short >>
__conditional_t
是条件模板,即当第一个模板参数成立时该模板为_If
否则为_Else
,亦即当参数包所占小于unsigned char
最大值时继承integral_constant<unsigned char, (unsigned char)sizeof...(_Types)>
否则继承integral_constant<unsigned short, (unsigned short)sizeof...(_Types)>
,而integral_constant<_Tp, __v>::type::value_type
其实也就是_Tp。所以__index_type
类型即是unsigned char
或是unsigned short
。
结构图
到此已经差不多把std::variant
结构过了一遍,这里以std::variant<int, float, string> va{std::in_place_index<2>, "str in variant"}
为例,来看看gdb中看到的结构:
三个_Variadic_union
共享内存:
成员函数
构造函数
默认构造
继承链底层的variant
将五个特殊成员及空构都声明为=default
:
1 2 3 4 5 6 variant () = default ;variant (const variant& __rhs) = default ;variant (variant&&) = default ;variant& operator =(const variant&) = default ; variant& operator =(variant&&) = default ; _GLIBCXX20_CONSTEXPR ~variant () = default ;
默认空构时构造父类_Variant_base
:
1 2 3 4 5 6 7 8 9 10 using _Base = _Move_assign_alias<_Types...>;constexpr _Variant_base() noexcept (_Traits<_Types...>::_S_nothrow_default_ctor) : _Variant_base(in_place_index<0 >) { } template <size_t _Np, typename ... _Args> constexpr explicit _Variant_base(in_place_index_t <_Np> __i, _Args&&... __args) : _Base(__i, std::forward<_Args>(__args)...) { }
中间的_Move_assign_alias
四个套娃类只各自解决一个特殊成员函数,最终"_Base"的构造会来到_Variant_storage
:
1 2 3 4 5 6 template <size_t _Np, typename ... _Args> constexpr _Variant_storage(in_place_index_t <_Np>, _Args&&... __args) : _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...), _M_index{_Np} { }
构造_Variadic_union
:
1 2 3 4 5 template <typename ... _Args> constexpr _Variadic_union(in_place_index_t <0 >, _Args&&... __args) : _M_first(in_place_index<0 >, std::forward<_Args>(__args)...) { }
构造_Uninitialized
:
1 2 3 4 5 template <typename ... _Args> constexpr _Uninitialized(in_place_index_t <0 >, _Args&&... __args) : _M_storage(std::forward<_Args>(__args)...) { }
默认构造时构造第一个元素,_Variant_storage
的_M_index
构造为0。
in_place_index构造
来看看另一个指定index的构造,variant
:
1 2 3 4 5 6 7 8 template <size_t _Np, typename ... _Args, typename _Tp = __to_type<_Np>, typename = enable_if_t <is_constructible_v<_Tp, _Args...>>> constexpr explicit variant (in_place_index_t <_Np>, _Args&&... __args) : _Base(in_place_index<_Np>, std::forward<_Args>(__args)...), _Default_ctor_enabler(_Enable_default_constructor_tag{}) { }
_Default_ctor_enabler
是上面提到的_Enable_default_constructor
的别名,这里就是标识这个父类是经由非默认构造函数进行构造。
_Base
的构造和默认构造类似,只是这里的_Np
是由函数模板参数指定,到_Variadic_union
中时经由另一个函数模板来完成构造:
1 2 3 4 5 template <size_t _Np, typename ... _Args> constexpr _Variadic_union(in_place_index_t <_Np>, _Args&&... __args) : _M_rest(in_place_index<_Np-1 >, std::forward<_Args>(__args)...) { }
这样在多嵌套层_Variadic_union
中经由多次模板函数调用找到对应index的_M_first
完成构造。
析构函数
主要析构在于_Variant_storage
中,关注下当实际类型不可平凡析构时_Variant_storage<false, _Types...>
的析构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 constexpr void _M_reset() { if (!_M_valid()) [[unlikely]] return ; std::__do_visit<void >([](auto && __this_mem) mutable { std::_Destroy(std::__addressof(__this_mem)); }, __variant_cast<_Types...>(*this )); _M_index = static_cast <__index_type>(variant_npos); } _GLIBCXX20_CONSTEXPR ~_Variant_storage() { _M_reset(); }
__do_visit
即是gcc内std::visit
的实现;_Destroy
也是gcc内调用析构的方法,在17标准后调用std::destroy_at
进行析构;std::__addressof
同为gcc实现内的方法,可以视为std::addressof
;所以这里的逻辑也比较清晰了,调用visit
方法访问实际对象,泛型lambda内实参类型确定后利用addressof
和destroy_at
对指定类型析构。
variant_npos
为constexpr size_t
固定为-1。
非成员函数
std::visit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 template <typename _Visitor, typename ... _Variants> constexpr __detail::__variant::__visit_result_t <_Visitor, _Variants...> visit (_Visitor&& __visitor, _Variants&&... __variants) { namespace __variant = std::__detail::__variant; if ((__variant::__as(__variants).valueless_by_exception () || ...)) __throw_bad_variant_access("std::visit: variant is valueless" ); using _Result_type = __detail::__variant::__visit_result_t <_Visitor, _Variants...>; using _Tag = __detail::__variant::__deduce_visit_result<_Result_type>; if constexpr (sizeof ...(_Variants) == 1 ) { using _Vp = decltype (__variant::__as(std::declval <_Variants>()...)); constexpr bool __visit_rettypes_match = __detail::__variant:: __check_visitor_results<_Visitor, _Vp>( make_index_sequence<variant_size_v<remove_reference_t <_Vp>>>()); if constexpr (!__visit_rettypes_match) { static_assert (__visit_rettypes_match, "std::visit requires the visitor to have the same " "return type for all alternatives of a variant" ); return ; } else return std::__do_visit<_Tag>( std::forward<_Visitor>(__visitor), static_cast <_Vp>(__variants)...); } else return std::__do_visit<_Tag>( std::forward<_Visitor>(__visitor), __variant::__as(std::forward<_Variants>(__variants))...); }
这里先调用valueless_by_exception
校验variant
是否有值,再检查参数包_Variants
内参数个数,个数为1时校验了_Visitor
对于_Variants
内所有成员返回值是否一致,再调用实现方法__do_visit
,这里元编程内容很多,鉴于此篇篇幅就不一一解读了。再来看下__do_visit
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 template <typename _Result_type, typename _Visitor, typename ... _Variants> constexpr decltype (auto ) __do_visit (_Visitor&& __visitor, _Variants&&... __variants) { if constexpr (sizeof ...(_Variants) == 0 ) { if constexpr (is_void_v<_Result_type>) return (void ) std::forward<_Visitor>(__visitor) () ; else return std::forward<_Visitor>(__visitor)(); } else { constexpr size_t __max = 11 ; using _V0 = typename _Nth_type<0 , _Variants...>::type; constexpr auto __n = variant_size_v<remove_reference_t <_V0>>; if constexpr (sizeof ...(_Variants) > 1 || __n > __max) { constexpr auto & __vtable = __detail::__variant::__gen_vtable< _Result_type, _Visitor&&, _Variants&&...>::_S_vtable; auto __func_ptr = __vtable._M_access(__variants.index ()...); return (*__func_ptr)(std::forward<_Visitor>(__visitor), std::forward<_Variants>(__variants)...); } else { _V0& __v0 = [](_V0& __v, ...) -> _V0& { return __v; }(__variants...); using __detail::__variant::_Multi_array; using __detail::__variant::__gen_vtable_impl; using _Ma = _Multi_array<_Result_type (*)(_Visitor&&, _V0&&)>; #ifdef _GLIBCXX_DEBUG # define _GLIBCXX_VISIT_UNREACHABLE __builtin_trap #else # define _GLIBCXX_VISIT_UNREACHABLE __builtin_unreachable #endif #define _GLIBCXX_VISIT_CASE(N) \ case N: \ { \ if constexpr (N < __n) \ { \ return __gen_vtable_impl<_Ma, index_sequence<N> >:: \ __visit_invoke(std::forward<_Visitor> (__visitor), \ std::forward<_V0> (__v0)); \ } \ else _GLIBCXX_VISIT_UNREACHABLE(); \ } switch (__v0.index ()) { _GLIBCXX_VISIT_CASE(0 ) _GLIBCXX_VISIT_CASE(1 ) _GLIBCXX_VISIT_CASE(2 ) _GLIBCXX_VISIT_CASE(3 ) _GLIBCXX_VISIT_CASE(4 ) _GLIBCXX_VISIT_CASE(5 ) _GLIBCXX_VISIT_CASE(6 ) _GLIBCXX_VISIT_CASE(7 ) _GLIBCXX_VISIT_CASE(8 ) _GLIBCXX_VISIT_CASE(9 ) _GLIBCXX_VISIT_CASE(10 ) case variant_npos: using __detail::__variant::__variant_idx_cookie; using __detail::__variant::__variant_cookie; if constexpr (is_same_v<_Result_type, __variant_idx_cookie> || is_same_v<_Result_type, __variant_cookie>) { using _Npos = index_sequence<variant_npos>; return __gen_vtable_impl<_Ma, _Npos>:: __visit_invoke(std::forward<_Visitor>(__visitor), std::forward<_V0>(__v0)); } else _GLIBCXX_VISIT_UNREACHABLE(); default : _GLIBCXX_VISIT_UNREACHABLE(); } #undef _GLIBCXX_VISIT_CASE #undef _GLIBCXX_VISIT_UNREACHABLE } } }
元编程内容依旧非常多,也不一一解读了,大致逻辑就是在单个variant
元素大于11个或者要访问的variant
多于1个时使用跳表访问每个variant
内容,否则就通过第一个variant
的index
进行访问。
std::holds_alternative
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 template <typename _Tp, typename ... _Types> constexpr bool holds_alternative (const variant<_Types...>& __v) noexcept { static_assert (__detail::__variant::__exactly_once<_Tp, _Types...>, "T must occur exactly once in alternatives" ); return __v.index () == std::__find_uniq_type_in_pack<_Tp, _Types...>(); } template <typename _Tp, typename ... _Types> constexpr size_t __find_uniq_type_in_pack() { constexpr size_t __sz = sizeof ...(_Types); constexpr bool __found[__sz] = { __is_same(_Tp, _Types) ... }; size_t __n = __sz; for (size_t __i = 0 ; __i < __sz; ++__i) { if (__found[__i]) { if (__n < __sz) return __sz; __n = __i; } } return __n; }
元编程的技巧,利用推导将variant
模板参数包拿到再利用该参数包找到指定类型的index。
std::get
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 template <typename _Tp, typename ... _Types> constexpr _Tp& get (variant<_Types...>& __v) { static_assert (__detail::__variant::__exactly_once<_Tp, _Types...>, "T must occur exactly once in alternatives" ); constexpr size_t __n = std::__find_uniq_type_in_pack<_Tp, _Types...>(); return std::get <__n>(__v); } template <size_t _Np, typename ... _Types> constexpr variant_alternative_t <_Np, variant<_Types...>>& get (variant<_Types...>& __v) { static_assert (_Np < sizeof ...(_Types), "The index must be in [0, number of alternatives)" ); if (__v.index () != _Np) __throw_bad_variant_access(__v.valueless_by_exception ()); return __detail::__variant::__get<_Np>(__v); } template <size_t _Np, typename _Variant> constexpr decltype (auto ) __get (_Variant&& __v) noexcept { return __variant::__get_n<_Np>(std::forward<_Variant>(__v)._M_u); }template <size_t _Np, typename _Union> constexpr decltype (auto ) __get_n (_Union&& __u) noexcept { if constexpr (_Np == 0 ) return std::forward<_Union>(__u) ._M_first._M_get () ; else if constexpr (_Np == 1 ) return std::forward<_Union>(__u)._M_rest._M_first._M_get(); else if constexpr (_Np == 2 ) return std::forward<_Union>(__u)._M_rest._M_rest._M_first._M_get(); else return __variant::__get_n<_Np - 3 >( std::forward<_Union>(__u)._M_rest._M_rest._M_rest); }
摘取了部分代码在上面,以std::get<ClassName>
形式调用时利用上面holds_alternative
提到的技巧找到index,最后递归找到实际index的_Uninitialized
。