您的位置:首页 > 编程语言 > C语言/C++

libc++ tuple源码剖析

2015-06-10 17:35 627 查看
  我们先来看这段代码:

[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)...>
利用
_Pred
unpack的时候生成
__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
掉。

  大概就是这样。下次有机会再继续研究其它的~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: