libc++ tuple源码剖析
2015-06-10 17:35
627 查看
我们先来看这段代码:
1. 一旦遇到一个为
2. 如果只剩一个元素它还为
3. 如果只剩下一个元素,当前元素为
4. 如果当前元素为
接着是很重要的
这里的
为了区分同样是模板函数中参数的不同作用,libc++使用类似Tag Dispatch的技术。
那么为什么是0,1,2呢?看这段代码:
也就是说
1. 当
2. 如果使用
1. 如果可以使用
2. 如果不使用,那么值为 2
一切都是这样的自然!
根据上文分析过的
1. 如果
1.
2. 不是一样的,那么只有当使用_Tp可以构造出_Hp时,该构造函数生效。
2. 根据使用
这段
可以看到,
这种形式的构造函数可以说是leaf的核心了。它把
这段里的
a template argument list
function call
as parameter types in a function type
发生,所以我是没办法赤裸裸地
好了,万事俱备,只欠东风了。是时候上
也就是说,
把这个分析完,我们的分析也就可以告一段落了。分析一下
参数的数量小于或等于本
这些传进去的参数要能够转换成
剩下的要可以默认构造
Ok !接下来,告诉
传进去的参数都可以构造哪个区间
这一部分的
没传进去的参数对应的上述部分
一切都初始化好啦!现在再看
这段代码步骤如下:
1.
2.
3.
4. 如果搜索到头,value为-1。如果在第二次搜索过程中再次发现了
大概就是这样。下次有机会再继续研究其它的~
[code]// __lazy_and template <bool _Last, class ..._Preds> struct __lazy_and_impl; template <class ..._Preds> struct __lazy_and_impl<false, _Preds...> : false_type {}; template <> struct __lazy_and_impl<true> : true_type {}; template <class _Pred> struct __lazy_and_impl<true, _Pred> : integral_constant<bool, _Pred::type::value> {}; template <class _Hp, class ..._Tp> struct __lazy_and_impl<true, _Hp, _Tp...> : __lazy_and_impl<_Hp::type::value, _Tp...> {}; template <class _P1, class ..._Pr> struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> {}; // __lazy_not template <class _Pred> struct __lazy_not : integral_constant<bool, !_Pred::type::value> {};
__lazy_and借助
__lazy_and_impl来实现编译期的 and 操作。大概实现过程是这样:
1. 一旦遇到一个为
false,终止特化,为
false_type;
2. 如果只剩一个元素它还为
true,那么为
true_type;
3. 如果只剩下一个元素,当前元素为
true,那么检查下一个元素;
4. 如果当前元素为
true而且剩余元素不为空,那么继续检查接下来的元素;
__lazy_not仅仅是简单取逻辑反。
接着是很重要的
__tuple_indices(C++ 14 可使用
integer_sequence代替)
[code]// __make_tuple_indices template <size_t...> struct __tuple_indices {}; template <size_t _Sp, class _IntTuple, size_t _Ep> struct __make_indices_imp; template <size_t _Sp, size_t ..._Indices, size_t _Ep> struct __make_indices_imp<_Sp, __tuple_indices<_Indices...>, _Ep> { typedef typename __make_indices_imp<_Sp+1, __tuple_indices<_Indices..., _Sp>, _Ep>::type type; }; template <size_t _Ep, size_t ..._Indices> struct __make_indices_imp<_Ep, __tuple_indices<_Indices...>, _Ep> { typedef __tuple_indices<_Indices...> type; }; template <size_t _Ep, size_t _Sp = 0> struct __make_tuple_indices { static_assert(_Sp <= _Ep, "__make_tuple_indices input error"); typedef typename __make_indices_imp<_Sp, __tuple_indices<>, _Ep>::type type; };
__tuple_indices是一堆
std::size_t。
__make_indices_imp可以“生成”从
_Sp(Start Point?)到
_Ep(End Point?)的
__tuple_indices。
[code]// __tuple_types template <class ..._Tp> struct __tuple_types {}; template <size_t _Ip> class _LIBCPP_TYPE_VIS_ONLY tuple_element<_Ip, __tuple_types<> > { public: static_assert(_Ip == 0, "tuple_element index out of range"); static_assert(_Ip != 0, "tuple_element index out of range"); }; template <class _Hp, class ..._Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_element<0, __tuple_types<_Hp, _Tp...> > { public: typedef _Hp type; }; template <size_t _Ip, class _Hp, class ..._Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_element<_Ip, __tuple_types<_Hp, _Tp...> > { public: typedef typename tuple_element<_Ip-1, __tuple_types<_Tp...> >::type type; }; template <class ..._Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size<__tuple_types<_Tp...> > : public integral_constant<size_t, sizeof...(_Tp)> { };
这里的
tuple_element根据
_Ip获取元素。
tuple_size可以获取到
tuple的
size。
[code]template <size_t _Ip, class _Hp, bool> class __tuple_leaf { _Hp value; //.... template <class _Tp, class _Alloc> _LIBCPP_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t) : value(_VSTD::forward<_Tp>(__t)) {/*...*/} template <class _Tp, class _Alloc> _LIBCPP_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t) : value(allocator_arg_t(), __a, _VSTD::forward<_Tp>(__t)) {/*...*/} template <class _Tp, class _Alloc> _LIBCPP_INLINE_VISIBILITY explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t) : value(_VSTD::forward<_Tp>(__t), __a) {/*...*/} _LIBCPP_INLINE_VISIBILITY int swap(__tuple_leaf& __t) _NOEXCEPT_(__is_nothrow_swappable<__tuple_leaf>::value) { _VSTD::swap(*this, __t); return 0; } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return value;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return value;} };
tuple_leaf根据类是否为
final实行空基类优化。其中,模板参数
_Ip为该
leaf的
Index,
Hp为存储值的类型。
bool表明是不是
final。
tuple_leaf的默认构造函数根据
value的默认构造是否为
noexcept的决定
leaf的构造函数是否为
noexcept。
为了区分同样是模板函数中参数的不同作用,libc++使用类似Tag Dispatch的技术。
integral_constant<int,0>表示是allocator,1表示使用
allocator_arg,2表示不使用
allocator_arg,
tuple_leaf还接收与
_Hp类型不同的参数来构造
value。
那么为什么是0,1,2呢?看这段代码:
[code] // allocator construction template <class _Tp, class _Alloc, class ..._Args> struct __uses_alloc_ctor_imp { static const bool __ua = uses_allocator<_Tp, _Alloc>::value; static const bool __ic = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value; static const int value = __ua ? 2 - __ic : 0; }; template <class _Tp, class _Alloc, class ..._Args> struct __uses_alloc_ctor : integral_constant<int, __uses_alloc_ctor_imp<_Tp, _Alloc, _Args...>::value> {};
也就是说
1. 当
_Tp不使用
allocator时,
value为 0
2. 如果使用
1. 如果可以使用
allocator_arg_t构造,那么
value为 1
2. 如果不使用,那么值为 2
一切都是这样的自然!
[code] template <class _Tp, class = typename enable_if< __lazy_and< __lazy_not<is_same<typename decay<_Tp>::type, __tuple_leaf>> , is_constructible<_Hp, _Tp> >::value >::type > _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value)) : value(_VSTD::forward<_Tp>(__t))
根据上文分析过的
__lazy_and,这段代码可以理解为:
1. 如果
1.
_Tp的类型是这个
__tuple_leaf,那么不使用该构造函数(应该使用copy constructor)
2. 不是一样的,那么只有当使用_Tp可以构造出_Hp时,该构造函数生效。
2. 根据使用
_Tp构造
_Hp是否为
noexcept来决定本构造函数的
noexcept。
[code]template <bool ..._Pred> struct __all : is_same<__all<_Pred...>, __all<(_Pred, true)...>> { }; template <class _Tp> struct __all_default_constructible; template <class ..._Tp> struct __all_default_constructible<__tuple_types<_Tp...>> : __all<is_default_constructible<_Tp>::value...> { };
这段
__all代码很有意思。
(_Pred,true)的值为
true,而
__all<(_Pred,true)...>利用
_Predunpack的时候生成
__all<true,true,...>,如果前面的
__all<_Pred...>和这个类型相等,那么说明
_Pred...全
true.
__all_default_constructible则用来判断
__tuple_types中的所有元素是否均可默认构造。
[code]template<class _Indx, class ..._Tp> struct __tuple_impl; template<size_t ..._Indx, class ..._Tp> struct __tuple_impl<__tuple_indices<_Indx...>, _Tp...> : public __tuple_leaf<_Indx, _Tp>...
__tuple_impl很重要,是
tuple的关键部分。
[code]// __tuple_impl template<class _Indx, class ..._Tp> struct __tuple_impl; template<size_t ..._Indx, class ..._Tp> struct __tuple_impl<__tuple_indices<_Indx...>, _Tp...> : public __tuple_leaf<_Indx, _Tp>... { //.... };
可以看到,
__tuple_impl继承自一堆
__tuple_leaf<_Indx, _Tp>。每个 leaf 有自己的 Index 和类型。
[code]template <size_t ..._Uf, class ..._Tf, size_t ..._Ul, class ..._Tl, class ..._Up> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit __tuple_impl(__tuple_indices<_Uf...>, __tuple_types<_Tf...>, __tuple_indices<_Ul...>, __tuple_types<_Tl...>, _Up&&... __u) _NOEXCEPT_((__all<is_nothrow_constructible<_Tf, _Up>::value...>::value && __all<is_nothrow_default_constructible<_Tl>::value...>::value)) : __tuple_leaf<_Uf, _Tf>(_VSTD::forward<_Up>(__u))..., __tuple_leaf<_Ul, _Tl>()... {}
这种形式的构造函数可以说是leaf的核心了。它把
tuple分为两部分,第一个部分是使用
___u进行初始化的部分,而另一部分是默认构造的部分。这样就可以实现类似这样的东西:
[code] std::tuple<int,char,float>t2{0.f};
[code] template <class _Tuple> _LIBCPP_INLINE_VISIBILITY typename enable_if < __tuple_assignable<_Tuple, tuple<_Tp...> >::value, __tuple_impl& >::type operator=(_Tuple&& __t) _NOEXCEPT_((__all<is_nothrow_assignable<_Tp&, typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>::value...>::value)) { __swallow(__tuple_leaf<_Indx, _Tp>::operator=(_VSTD::forward<typename tuple_element<_Indx, typename __make_tuple_types<_Tuple>::type>::type>(_VSTD::get<_Indx>(__t)))...); return *this; }
这段里的
swallow是很有意思的。由于可变模板的解包只能在 (N2080)
a template argument list
function call
as parameter types in a function type
发生,所以我是没办法赤裸裸地
operator =一堆的。有了
swallow,这样就可以解包了。这也就是为什么
__tuple_leaf::swap的返回值类型为
int。
好了,万事俱备,只欠东风了。是时候上
tuple的真身了:
[code] template <class ..._Tp> class _LIBCPP_TYPE_VIS_ONLY tuple { typedef __tuple_impl<typename __make_tuple_indices<sizeof...(_Tp)>::type, _Tp...> base; base base_; //... public:
也就是说,
tuple内部有一个
__tuple_impl成员
base。
[code] template <class ..._Up, typename enable_if < sizeof...(_Up) <= sizeof...(_Tp) && __tuple_convertible < tuple<_Up...>, typename __make_tuple_types<tuple, sizeof...(_Up) < sizeof...(_Tp) ? sizeof...(_Up) : sizeof...(_Tp)>::type >::value && __all_default_constructible< typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up) < sizeof...(_Tp) ? sizeof...(_Up) : sizeof...(_Tp)>::type >::value, bool >::type = false > _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 tuple(_Up&&... __u) _NOEXCEPT_(( is_nothrow_constructible<base, typename __make_tuple_indices<sizeof...(_Up)>::type, typename __make_tuple_types<tuple, sizeof...(_Up)>::type, typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type, typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type, _Up... >::value )) : base_(typename __make_tuple_indices<sizeof...(_Up)>::type(), typename __make_tuple_types<tuple, sizeof...(_Up)>::type(), typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(), typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(), _VSTD::forward<_Up>(__u)...) {}
把这个分析完,我们的分析也就可以告一段落了。分析一下
enable_if:
参数的数量小于或等于本
tuple的总参数数量
这些传进去的参数要能够转换成
tuple需要的参数类型
剩下的要可以默认构造
Ok !接下来,告诉
__tuple_impl
传进去的参数都可以构造哪个区间
这一部分的
tuple的类型
没传进去的参数对应的上述部分
一切都初始化好啦!现在再看
get
[code] // get by type template <typename _T1, size_t _Idx, typename... _Args> struct __find_exactly_one_t_helper; // -- find exactly one template <typename _T1, size_t _Idx, typename... _Args> struct __find_exactly_one_t_checker { static constexpr size_t value = _Idx; // Check the rest of the list to make sure there's only one static_assert ( __find_exactly_one_t_helper<_T1, 0, _Args...>::value == -1, "type can only occur once in type list" ); }; template <typename _T1, size_t _Idx> struct __find_exactly_one_t_helper <_T1, _Idx> { static constexpr size_t value = -1; }; template <typename _T1, size_t _Idx, typename _Head, typename... _Args> struct __find_exactly_one_t_helper <_T1, _Idx, _Head, _Args...> { static constexpr size_t value = std::conditional< std::is_same<_T1, _Head>::value, __find_exactly_one_t_checker<_T1, _Idx, _Args...>, __find_exactly_one_t_helper <_T1, _Idx+1, _Args...> >::type::value; }; template <typename _T1, typename... _Args> struct __find_exactly_one_t { static constexpr size_t value = __find_exactly_one_t_helper<_T1, 0, _Args...>::value; static_assert ( value != -1, "type not found in type list" ); }; template <class _T1, class... _Args> inline _LIBCPP_INLINE_VISIBILITY constexpr _T1& get(tuple<_Args...>& __tup) noexcept { return _VSTD::get<__find_exactly_one_t<_T1, _Args...>::value>(__tup); }
这段代码步骤如下:
1.
__find_exactly_one_t使用
__find_exactly_one_t_helper
2.
__find_exactly_one_t_helper开始校对
_Args...中是否有
_T1,一旦发现,转到
__find_exactly_one_t_checker,若没发现,继续。
3.
__find_exactly_one_t_checker将当前
_Idx存储下来,继续搜索。
4. 如果搜索到头,value为-1。如果在第二次搜索过程中再次发现了
_T1,那么
__find_exactly_one_t_helper的
value就是
__find_exactly_one_t_checker<_T1, _Idx, _Args...>中的
value,的值就不为-1,
static_assert掉。
大概就是这样。下次有机会再继续研究其它的~
相关文章推荐
- NYOJ 57 6174问题
- (1)风色从零单排《C++ Primer》 一个简单的c++程序
- VC++模拟键盘输入(keybd_event() 、 PostMessage() /SendMessage()、SendInput())详解
- C++的参数传递机制[转]
- C++中的友元函数的总结
- 2015年第十四周oj刷提:C++ 习题 输出日期时间--友元函数
- C++10.3.5 map : : insert 的使用(下)(有不懂)
- 聊天系统中的用户列表并发问题分析
- C语言 判断二叉树是不是平衡树
- C语言 判断二叉树是不是平衡树
- 第十四周 项目4-处理c++源代码的程序(1)
- C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码
- c++默认的构造函数中调用带参数的构造函数
- C语言 打印路径节点值的和为指定和的所有路径
- 二叉排序树的C++实现
- C语言 打印从根节点到叶节点的所有路径
- 为什么C++程序无法打开相对路径的文件?
- C#调用C++的DLL各种问题
- C语言-编译
- C++头文件编译问题