(三)boost::lambda源码分析

 本文是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<<' '这种形式。

这只是冰山一角,已足以展示其复杂性。

 

 

 

 

你可能感兴趣的:(null,Class,action,lambda,functor,tuples)