boost::mpl::list 源码分析

本文详细分析了boost::mpl::list的源码,包括list的大小定义、预处理头文件、宏展开过程以及list在编译时的时间复杂度。讨论了list的结构,迭代器的实现,特别是size()函数的计算方式,以及如何通过has_tag宏来检查序列的标记。

使用 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的内容。下面讨论beginend 这两个迭代器对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

上面已经讨论了这些代码。

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yshuise

权术横行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值