本文是lambda分析篇最重要的一篇。lambda源码比较庞大(把宏全部展开),只是对其中的小部分进行分析,小部分足以展示其难度和运行机理。
boost源码给我的感觉对基础知识要求很高,是对知识正确的运用(我们的朋友们已经走向了另一条路,喜马拉雅上还是要从中国这方爬比较合适)。lambda源码对模板技术的运用很高,比其它代码如pool,shared_ptr等等都要厉害。总体来看mpl源码是元编程的皎皎者,但是很难运用在实际的工作中。lambda应该是实际运用的出色者。
先看下面的代码:
首先,主要研究lambda的运用:
打印出容器中的元素,这些元素显然是连续的。如果要分开,可以写成:
简单的增加了后面的' '或是std::endl将使模板参数变得异常的复杂。
因此,先考虑不那么复杂的语句:
std::cout<<_1
上面语句一定先要展开_1,这个在源码中被定义成这样的形式:
上面要获得lambda_fuctor这个模板,它是由宏扩展而成:
上面这个流程先讨论到这儿。实际上由于这个流程指向的方向是非常复杂,只有充满勇气人才能人继续走下去。
前面讨论到:
std::cout<<_1
由于这个for_each:
所以实际上std::cout<<_1应该是这样的形式:
根据重载操作符的<<的规则,第一个参数必是std::cout,那么这个
函看起来是这个样子:
上面的operator<<从何而来?
由此语句展开:
展开过后为:
这个函数同相对应:
也就是:
A --------------------> std::basic_ostream<char,std::char_traits<char> >
boost::lambda::lambda_functor<boost::lambda::placeholder<1> > ------> const lambda_functor<Arg>&
而返回类型是:
为什么返回类型如此重要,因为如果后面还有输出内容,那么不能少。std::cout<<_1<<' ',输出
' '少不了返回类型。
convert_ostream_to_ref_others_to_c_plain_by_default这个元函数类不讨论了。它的主要内容在
(一)boost::lambda分析中已经讨论了。
这样最终构造一个lambda_functor对象。
然后在for_each中,调用
lambda_functor调用如下:
上面的operator()中的call调用实际上:
std::cout<<_1与std::cout<<_1<<' '差别在哪儿?在于传入的args这个模板参数不同。
std::cout<<_1的模板参数类型是:
而std::cout<<_1<<' '的类型是:
可见要复杂得多。里面的boost::tuples::null_type可以略去不看。
如果仔细的阅读,还是可以理解的。不理解是不行的,只有理解了才能懂得其道理。
通过模板的递归调用最终还是std::cout<<_1<<' '这种形式。
这只是冰山一角,已足以展示其复杂性。