使用 list 的方法如下:
#include <iostream>
#include <boost/mpl/list/list10.hpp>
#include <boost/mpl/size.hpp>
using namespace boost;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
typedef mpl::list3<int,double,int>::type r;
cout<<mpl::size<r>::type::value<<endl;
}
list3只能存放3个元素,如果要存放12(list12<...>)元素,那么头文件需要变成list20.hpp。
小于10等于10个元素都可以用头文件list10.hpp。
同时无需指定一个明确的值。比如:list<int,float,double...>等。同时相应的头文件也必须做出改变。
size函数求存放元素的个数。
这儿有两个版本的list(按生成方式的不同)。
一个是手工写成,另外一个依靠宏扩展而成。先讨论手工写成的list10.hpp。
#include <boost/mpl/list/list10.hpp> 包含的源码为:
#if !defined(BOOST_MPL_PREPROCESSING_MODE)//如果没有定义这个宏,就包括下面这个文件。
# include <boost/mpl/list/list0.hpp>//放在后面讨论
#endif
#include <boost/mpl/aux_/config/use_preprocessed.hpp>
这个文件包括的源代码对宏BOOST_MPL_PREPROCESSING进行了定义,源码拷贝如下:
#ifndef BOOST_MPL_AUX_CONFIG_USE_PREPROCESSED_HPP_INCLUDED
#define BOOST_MPL_AUX_CONFIG_USE_PREPROCESSED_HPP_INCLUDED
// Copyright Aleksey Gurtovoy 2000-2004
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/mpl for documentation.
// $Id: use_preprocessed.hpp 49267 2008-10-11 06:19:02Z agurtovoy $
// $Date: 2008-10-11 02:19:02 -0400 (Sat, 11 Oct 2008) $
// $Revision: 49267 $
#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS //这句就是上面头文件的内容。
#endif // BOOST_MPL_AUX_CONFIG_USE_PREPROCESSED_HPP_INCLUDED
这儿我们先讨论手工写成的代码,而不是依靠宏扩展而成的代码,因此可以把
这个宏注释掉
#if !defined(BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS) /
&& !defined(BOOST_MPL_PREPROCESSING_MODE) //由于我们注释了这个宏,所以
//包括下面两个文件。
# define BOOST_MPL_PREPROCESSED_HEADER list10.hpp
# include <boost/mpl/list/aux_/include_preprocessed.hpp>
//下面这个版本是宏生成版本,暂时不考虑。先考虑手工代码。
#else
# include <boost/preprocessor/iterate.hpp>
namespace boost { namespace mpl {
# define BOOST_PP_ITERATION_PARAMS_1 /
(3,(1, 10, <boost/mpl/list/aux_/numbered.hpp>))
# include BOOST_PP_ITERATE()
}}
#endif // BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
#endif // BOOST_MPL_LIST_LIST10_HPP_INCLUDED
这儿我们先讨论手工写成的代码,而不是依靠宏扩展而成的代码,因此可以把
上面那个BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS宏注释掉。
上面的include_preprocessed.hpp包含的源文件精简为:
# define AUX778076_HEADER / aux_/preprocessed/plain/BOOST_MPL_PREPROCESSED_HEADER / /**/ # include BOOST_PP_STRINGIZE(boost/mpl/list/AUX778076_HEADER)
BOOST_PP_STRINGIZE 宏定义在文件
#include <boost/preprocessor/stringize.hpp>中(当前编译器MSVC9.0)
代码精简为:
# define BOOST_PP_STRINGIZE(text) BOOST_PP_STRINGIZE_A((text)) # define BOOST_PP_STRINGIZE_A(arg) BOOST_PP_STRINGIZE_I arg # define BOOST_PP_STRINGIZE_I(text) #text //#text扩展成"text"
综上所述,
#include BOOST_PP_STRINGIZE(boost/mpl/list/AUX778076_HEADER)
全部展开为:
#include "boost/mpl/list/aux_/preprocessed/plain/list10.hpp"
下面分别举能存放一个元素,两个元素,三个元素的序列,其余的与此相似,不予讨论。
分别是list1、list2、list3。
template<
typename T0
>
struct list1
: l_item<
long_<1> //这个参数代表size,指示能存放一个元素。下面定义
, T0 //这就是存放的那个元素。
, l_end
>
{
typedef list1 type;
};
template<
typename T0, typename T1
>
struct list2
: l_item<
long_<2>//在下面定义。
, T0
, list1<T1>
>
{
typedef list2 type;
};
template<
typename T0, typename T1, typename T2
>
struct list3
: l_item<
long_<3>
, T0
, list2< T1,T2 >
>
{
typedef list3 type;
};
上面的long_定义如下:
//上面的long_定义如下:
template<long N>
struct long_
{
static long value = N ; //当前的值
typedef long type;
typedef long_ value_type;
typedef integral_c_tag tag; //标记作用,在其他地方定义或是声明。
typedef long_<static_cast<long>(value+1)> next; //假如当前为:long_<1>,下一个就是long_<2>
typedef long_<static_cast<long>(value-1)> prior;//假如当前内容为:long_<1>,上一个就是long_<0>
// enables uniform function call syntax for families of overloaded
// functions that return objects of both arithmetic ('int', 'long',
// 'double', etc.) and wrapped integral types (for an example, see
// "mpl/example/power.cpp")
//对“()”进行重载返回当前的值,用法为:long_<5>(),这个值就是5,同上面的vaule 代表一个意思。
operator long() const { return static_cast<long>(this->value); }
};
//static要在类外面定义。enum就不需要。
template<long N>
long long_<N>::value;
基类l_item如下:
struct list_tag; //作为标记
//l_item的定义如下:
template<
typename Size //如果存放一个元素,从上面看来应该是long_<1>,两个是long_<2>
, typename T
, typename Next
>
struct l_item
{
// agurt, 17/jul/03: to facilitate the deficient 'is_sequence' implementation
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)//vc7.0 版本
typedef int begin; //vc7才用这个版本
#endif
typedef aux::list_tag tag;//aux是名词空间,list_tag在aux里面.
typedef l_item type;
typedef Size size;//list3对应long_<3>,list2对应long_<2>,list1对应long_<1>
typedef T item; //当前的元素
typedef Next next; //下一个节点.list3的下一个节点是list2, list2 的下一个节点是list1.
};
比较 mpl::vector和mpl::list的结构就可以看出:
因为这是元编程,运行都是O(1)时间,区别在于编译时间的不同。
这儿的编译时间和运行时时间的复杂度还是有区别的。只是用类似于运行时的时间复杂度来
衡量。在编译的时候,vector可以很随便的访问类中的任何一个元素,因为其中一种vector
的实现方式,实际是把每一个元素都写在了结构里面:item0,item1,item2,item3.....
而list则不同,list在访问首元素和尾元素倒是很快的。但是如果是中间的元素呢?只能通过迭代器来遍历,
这就像链表一样,一个节点一个节点的遍历。当然就是线性时间复杂度了:O(n)
迭代器 :
struct l_end //这个类起一个结束的标记作用。 { #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)//vc7.0 版本 typedef int begin; #endif typedef aux::list_tag tag; typedef l_end type; typedef long_<0> size; }; struct l_iter_tag;//迭代器的标记 //迭代器标志。int_同long_一样。只是在long的地方用int来替换。 struct forward_iterator_tag : int_<0> { typedef forward_iterator_tag type; };
以上就是list的内容。下面讨论begin 和end 这两个迭代器对list是怎样实现的:
/*
begin<l>::type
下面讨论begin算法怎样实习取元素的。
*/
template<
typename BOOST_MPL_AUX_NA_PARAM(Sequence)
>
struct begin
{ //sequence_tag这是一个标记.
typedef typename sequence_tag<Sequence>::type tag_;
typedef typename begin_impl< tag_ > //在下面定义。
::template apply< Sequence >::type type;
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,begin,(Sequence))
};
template<>
struct begin_impl< aux::list_tag >
{
template< typename List > struct apply //模板参数是list
{ //从下面可以看出l_iter定义里面并没有什么,关键信息是:List::type
typedef l_iter<typename List::type> type;
};
};
/*
end<l>::type 指向 list 尾部的迭代器
*/
template<
typename BOOST_MPL_AUX_NA_PARAM(Sequence) // typename Sequence
>
struct end
{
typedef typename sequence_tag<Sequence>::type tag_; //
typedef typename end_impl< tag_ > //end_impl全特化代码在下面。
::template apply< Sequence >::type type;
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,end,(Sequence))
};
template<>
struct end_impl< aux::list_tag >
{
template< typename > struct apply
{
typedef l_iter<l_end> type; //最后还是以l_end作为迭代器的参数。
};
};
//l_iter迭代调用如下, 最后 end<l>::type返回 l_iter<l_end>迭代器。
template< typename Node >
struct l_iter
{
typedef aux::l_iter_tag tag;
typedef forward_iterator_tag category;
};
size(list) 算法:
size类源代码为:
template<
typename BOOST_MPL_AUX_NA_PARAM(Sequence)
>
struct size
: aux::msvc_eti_base<
typename size_impl< typename sequence_tag<Sequence>::type >
::template apply< Sequence >::type
>::type
{
};
size 继承 msvc_eti_base 类模板,
msvc_eti_base的源代码为:
template< typename T > struct msvc_eti_base : T { typedef T type; };
它继承模板参数,并以模板参数为type.
因此现在来看模板参数是什么:
template<> struct size_impl< aux::list_tag > { template< typename List > struct apply : List::size { }; };
size_impl的内嵌模板类apply,并没有type,但是上面的代码:::template apply< Sequence >::type
表明有type.这就是apply为什么要继承模板参数的原因,它可以访问基类的成员type。
这个type实际就是list。而获得了list这个类型就很容易的访问类里面的成员了。如果是
list3, 那么就可以访问size,而这儿的size就是long_<3>,对它求值long_<3>() = 3。
下面来看看list的tag(上面用到了):
template<
typename BOOST_MPL_AUX_NA_PARAM(Sequence)
>
struct sequence_tag
: aux::sequence_tag_impl<
::boost::mpl::aux::has_tag<Sequence>::value
, ::boost::mpl::aux::has_begin<Sequence>::value
>::template result2_<Sequence>
{
};
它是继承sequence_tag_impl
template< bool has_tag_, bool has_begin_ >
struct sequence_tag_impl
{
// agurt 24/nov/02: MSVC 6.5 gets confused in 'sequence_tag_impl<true>'
// specialization below, if we name it 'result_' here
template< typename Sequence > struct result2_;
};
# define AUX_CLASS_SEQUENCE_TAG_SPEC(has_tag, has_begin, result_type) /
template<> struct sequence_tag_impl<has_tag,has_begin> /
{ /
template< typename Sequence > struct result2_ /
{ /
typedef result_type type; /
}; /
}; /
/**/
AUX_CLASS_SEQUENCE_TAG_SPEC(true, true, typename Sequence::tag)
这个宏推出以下的代码:
template<> struct sequence_tag_impl<true,true>
{
template<typename Sequence> struct result2_
{
typedef Sequence::tag type;
};
};
AUX_CLASS_SEQUENCE_TAG_SPEC(true, false, typename Sequence::tag)
上面的宏推出:
template<> struct sequence_tag_impl<true,false>
{
template<typename Sequence> struct result2_
{
typedef Sequence::tag type;
};
};
has_tag必须成功,才能得到正确的类型。它获得标记就是list的tag。
has_tag是由一个宏来实现的:
#define BOOST_MPL_HAS_XXX_TRAIT_DEF(name) / BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(BOOST_PP_CAT(has_,name), name, false) /
宏定义代码:
# elif BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) /
|| BOOST_WORKAROUND(__IBMCPP__, <= 700)
// MSVC 7.1+ & VACPP
// agurt, 15/jun/05: replace overload-based SFINAE implementation with SFINAE
// applied to partial specialization to fix some apparently random failures
// (thanks to Daniel Wallin for researching this!)
# define BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(trait, name, default_) /
template< typename T > /
struct BOOST_PP_CAT(trait, _msvc_sfinae_helper) /
{ /
typedef void type; /
};/
/
template< typename T, typename U = void > /
struct BOOST_PP_CAT(trait,_impl_) /
{ /
BOOST_STATIC_CONSTANT(bool, value = false); /
typedef boost::mpl::bool_<value> type; /
}; /
/
template< typename T > /
struct BOOST_PP_CAT(trait,_impl_)< /
T /
, typename BOOST_PP_CAT(trait, _msvc_sfinae_helper)< typename T::name >::type /
> /
{ /
BOOST_STATIC_CONSTANT(bool, value = true); /
typedef boost::mpl::bool_<value> type; /
}; /
/
template< typename T, typename fallback_ = boost::mpl::bool_<default_> > /
struct trait /
: BOOST_PP_CAT(trait,_impl_)<T> /
{ /
}; /
/**/
经过推导以后为:
template<typename T>
struct has_tag__msvc_sfinae_helper
{
typedef void type;
};
template< typename T, typename U = void >
struct has_tag_impl_
{
BOOST_STATIC_CONSTANT(bool, value = false); //bool static value = false;
typedef boost::mpl::bool_<value> type;
};
template< typename T >
struct has_tag_impl_<
T
, typename has_tag__msvc_sfinae_helper< typename T::name >::type
>
{
BOOST_STATIC_CONSTANT(bool, value = true);
typedef boost::mpl::bool_<value> type;
};
template< typename T, typename fallback_ = boost::mpl::bool_<default_> >
struct trait
: has_tag_impl_<T>
{
};
上面的mpl::bool_的代码为:
template< bool C_ > struct bool_
{
BOOST_STATIC_CONSTANT(bool, value = C_);
typedef integral_c_tag tag;
typedef bool_ type;
typedef bool value_type;
operator bool() const { return this->value; }
};
实际上就是指如果这个序列有tag标记就返回true,即使这个序列没有元素值仍然返回正确的
值:
AUX_CLASS_SEQUENCE_TAG_SPEC(true, true, typename Sequence::tag)//list在这种情况下,正确
AUX_CLASS_SEQUENCE_TAG_SPEC(true, false, typename Sequence::tag)//list, true
AUX_CLASS_SEQUENCE_TAG_SPEC(false, true, nested_begin_end_tag)//list, false
AUX_CLASS_SEQUENCE_TAG_SPEC(false, false, non_sequence_tag)//list, false
上面已经讨论了这些代码。
本文详细分析了boost::mpl::list的源码,包括list的大小定义、预处理头文件、宏展开过程以及list在编译时的时间复杂度。讨论了list的结构,迭代器的实现,特别是size()函数的计算方式,以及如何通过has_tag宏来检查序列的标记。
453

被折叠的 条评论
为什么被折叠?



