您的位置:首页 > 其它

(三)boost::lambda源码分析

2010-10-03 11:32 295 查看
本文是lambda分析篇最重要的一篇。lambda源码比较庞大(把宏全部展开),只是对其中的小部分进行分析,小部分足以展示其难度和运行机理。

boost源码给我的感觉对基础知识要求很高,是对知识正确的运用(我们的朋友们已经走向了另一条路,喜马拉雅上还是要从中国这方爬比较合适)。lambda源码对模板技术的运用很高,比其它代码如pool,shared_ptr等等都要厉害。总体来看mpl源码是元编程的皎皎者,但是很难运用在实际的工作中。lambda应该是实际运用的出色者。



先看下面的代码:

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include "boost/lambda/lambda.hpp"
#include "boost/tuple/tuple.hpp"
//#include "boost/lambda/bind.hpp"
// Tuple to cons mapper --------------------------------------------------

int _tmain(int argc, _TCHAR* argv[])
{   
	using namespace boost::lambda;
	using namespace std;

	boost::tuple<int,double,string> triple(42, 3.245, "The amazing tuple!");
	int  a0  =  triple.get<0>();
	double  a1  =  triple.get<1>();
	string  a2  =  triple.get<2>();
	
	std::vector<int> vec(3);
	vec[0] = 12;
	vec[1] = 10;
	vec[2] = 7;

	//Transform using a lambda expression
	std::for_each(vec.begin(), vec.end(), std::cout<<_1);
	std::for_each(vec.begin(), vec.end(), std::cout<<_1<<' ');
	//std::transform(vec.begin(), vec.end(), vec.begin(), _1-= 4);
  
	return 0;
}


首先,主要研究lambda的运用:

std::for_each(vec.begin(), vec.end(), std::cout<<_1);


打印出容器中的元素,这些元素显然是连续的。如果要分开,可以写成:

std::cout<<_1<<' ' 或是std::cout<<_1<<std::endl;


简单的增加了后面的' '或是std::endl将使模板参数变得异常的复杂。

因此,先考虑不那么复杂的语句:

std::cout<<_1

上面语句一定先要展开_1,这个在源码中被定义成这样的形式:

boost::lambda::placeholder1_type& _1 = free1;
 boost::lambda::placeholder1_type free1 = boost::lambda::placeholder1_type();
 typedef const lambda_functor<placeholder<FIRST> >  placeholder1_type;
 template <int I> struct placeholder;
 
 template<> struct placeholder<FIRST> {
	 
	 template<class SigArgs> struct sig {
		 typedef typename detail::get_element_or_null_type<0, SigArgs>::type type;
	 };
	 
	 template<class RET, CALL_TEMPLATE_ARGS> 
		 RET call(CALL_FORMAL_ARGS) const { //这儿主要还是在于返回a
		 BOOST_STATIC_ASSERT(boost::is_reference<RET>::value); 
		 CALL_USE_ARGS; // does nothing, prevents warnings for unused args
		 return a; 
	 }
 };


上面要获得lambda_fuctor这个模板,它是由宏扩展而成:

BOOST_LAMBDA_BE2(operator<<, 
bitwise_action< leftshift_action>, 
A, 
const B, detail::convert_ostream_to_ref_others_to_c_plain_by_default)


上面这个流程先讨论到这儿。实际上由于这个流程指向的方向是非常复杂,只有充满勇气人才能人继续走下去。

前面讨论到:

std::cout<<_1

由于这个for_each:

template <class _InputIter, class _Function>
_Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
	__STL_REQUIRES(_InputIter, _InputIterator);
	for ( ; __first != __last; ++__first)
		__f(*__first); //std::cout<<_1(*first);
	return __f;
}


所以实际上std::cout<<_1应该是这样的形式:

std::cout<<_1(*first);


根据重载操作符的<<的规则,第一个参数必是std::cout,那么这个

函看起来是这个样子:

std::cout<< lambda_functor<placeholder<FIRST> >(*first);
上面语句调用的函数看起来向下面这个样子:
operator <<(std::basic_ostream<char, std::char_traits<char> >&,  boost::lambda::lambda_functor<boost::lambda::placeholder<1> >& )




上面的operator<<从何而来?

#define BOOST_LAMBDA_BE2(OPER_NAME, ACTION, CONSTA, CONSTB, CONVERSION)      /
	template<class A, class Arg>                                                 /
	inline const                                                                 /
	lambda_functor<                                                              /
	lambda_functor_base<                                                       /
    ACTION,                                                                  /
    tuple<typename CONVERSION <CONSTA>::type, lambda_functor<Arg> >        /
	>                                                                          /
	>                                                                            /
	OPER_NAME (CONSTA& a, const lambda_functor<Arg>& b) {                      /
	return                                                                     /
    lambda_functor_base<                                                     /
	ACTION,                                                                /
	tuple<typename CONVERSION <CONSTA>::type, lambda_functor<Arg> >      /
    >                                                                        /
	(tuple<typename CONVERSION <CONSTA>::type, lambda_functor<Arg> >(a, b)); /
}


由此语句展开:

BOOST_LAMBDA_BE2(operator<<, bitwise_action< leftshift_action>, A, const B, detail::convert_ostream_to_ref_others_to_c_plain_by_default)


展开过后为:

//上面的宏扩展成下面这个样子

   template<class A, class Arg>
   inline const
   lambda_functor<
   lambda_functor_base<
   bitwise_action< leftshift_action>,
   tuple<typename detail::convert_ostream_to_ref_others_to_c_plain_by_default<A>::type, lambda_functor<Arg> >
   >
   >
   operator<<  (A& a, const lambda_functor<Arg>& b){//operator<<是重载操作符,std::cout<<_1,std::cout对应第一个参数,_1对应第二参数。
   return
   lambda_functor_base<
   bitwise_action< leftshift_action>,
   tuple<typename detail::convert_ostream_to_ref_others_to_c_plain_by_default<A>::type, lambda_functor<Arg> >
   >
   (tuple<typename detail::convert_ostream_to_ref_others_to_c_plain_by_default<A>::type, lambda_functor<Arg> >(a, b));

}




这个函数同相对应:

operator <<(std::basic_ostream<char, std::char_traits<char> >&,  boost::lambda::lambda_functor<boost::lambda::placeholder<1> >& )


也就是:

A --------------------> std::basic_ostream<char,std::char_traits<char> >

boost::lambda::lambda_functor<boost::lambda::placeholder<1> > ------> const lambda_functor<Arg>&

而返回类型是:

const boost::tuples::tuple<std::basic_ostream<char,std::char_traits<char> > &,boost::lambda::lambda_functor<boost::lambda::placeholder<1> >,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> &


为什么返回类型如此重要,因为如果后面还有输出内容,那么不能少。std::cout<<_1<<' ',输出

' '少不了返回类型。

convert_ostream_to_ref_others_to_c_plain_by_default这个元函数类不讨论了。它的主要内容在

(一)boost::lambda分析中已经讨论了。

这样最终构造一个lambda_functor对象。

然后在for_each中,调用

template <class _InputIter, class _Function>
_Function for_each(_InputIter __first, _InputIter __last, _Function __f) {
	__STL_REQUIRES(_InputIter, _InputIterator);
	for ( ; __first != __last; ++__first)
		__f(*__first); //这句就是调用lambda_functor(*_first),因为lambda_functor对operator()进行了重载,所以最终是对operator()的调用。

	return __f;
}


lambda_functor调用如下:

template <class T>
class lambda_functor : public T 
{
public:
  typedef T inherited;

  lambda_functor() {}
  lambda_functor(const lambda_functor& l) : inherited(l) {}

  lambda_functor(const T& t) : inherited(t) {}

  template <class SigArgs> struct sig {
    typedef typename inherited::template 
      sig<typename SigArgs::tail_type>::type type;
  };

  // Note that this return type deduction template is instantiated, even 
  // if the nullary 
  // operator() is not called at all. One must make sure that it does not fail.
  typedef typename 
    inherited::template sig<null_type>::type
      nullary_return_type;

  nullary_return_type operator()() const { 
    return inherited::template 
      call<nullary_return_type>
        (cnull_type(), cnull_type(), cnull_type(), cnull_type()); 
  }
//对这个operator进行调用
  template<class A>
  typename inherited::template sig<tuple<A&> >::type
  operator()(A& a) const { 
    return inherited::template call<
      typename inherited::template sig<tuple<A&> >::type
    >(a, cnull_type(), cnull_type(), cnull_type());
  }
.................
................
...........


上面的operator()中的call调用实际上:

template<class Args>
class  lambda_functor_base<bitwise_action<leftshift_action>, Args>{
public:
	Args  args;
public:
	explicit lambda_functor_base(const Args& a):args(a){}
	template<class RET, class A, class B, class C, class Env>
	RET call(A& a, B& b, C& c, Env& env)const{
               //这儿快到终点了。get<0>(args)参数这儿代表std::cout;
               //get<1>(args)代表12,所以就像这样std::cout<<12
		return  detail::select(boost::tuples::get<0>(args), a, b, c, env)
			<<
			detail::select(boost::tuples::get<1>(args), a, b, c, env);
	}

	template<class SigArgs> struct sig{
		typedef typename
			detail::binary_rt<bitwise_action<leftshift_action>, Args, SigArgs>::type type; 
	};
};


std::cout<<_1与std::cout<<_1<<' '差别在哪儿?在于传入的args这个模板参数不同。

std::cout<<_1的模板参数类型是:

const boost::tuples::tuple<std::basic_ostream<char,std::char_traits<char> > &,
      boost::lambda::lambda_functor<boost::lambda::placeholder<1> >,
      boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
	  boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
      boost::tuples::null_type,boost::tuples::null_type> &


而std::cout<<_1<<' '的类型是:

const boost::tuples::tuple<boost::lambda::lambda_functor<
	boost::lambda::lambda_functor_base<
	boost::lambda::bitwise_action<boost::lambda::leftshift_action>,
	boost::tuples::tuple<std::basic_ostream<char,std::char_traits<char> > &,
	boost::lambda::lambda_functor<boost::lambda::placeholder<1> >,
	boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
	boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
	boost::tuples::null_type,boost::tuples::null_type> > >,char const ,
	boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
	boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,
	boost::tuples::null_type,boost::tuples::null_type> &


可见要复杂得多。里面的boost::tuples::null_type可以略去不看。

如果仔细的阅读,还是可以理解的。不理解是不行的,只有理解了才能懂得其道理。

通过模板的递归调用最终还是std::cout<<_1<<' '这种形式。

这只是冰山一角,已足以展示其复杂性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: