本文是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<<' '这种形式。
这只是冰山一角,已足以展示其复杂性。