|
(三)lambda
这是一个绝妙的库,我在学习他的时候第一个反映就是震惊,“什么,代码还可以这样写!?”,但是在思考以后我的反映是对作者的想象力的赞叹和恒心的佩服,为什么呢?请先看个简单的例子,然后你自然就明白了。
我们写代码的时候经常写出这样的代码:
using namespace std;
extern list<int&> m_list;
template <class T>
struct plus
{
T& i;
plus(T& ii) : i(ii) { }
void operator()(const T& j) const
{
cout << j;
cout << (i + j);
}
}
int i = 0;
for_each(m_list.begin(), m_list.end(), plus(i));
我们已经很满足了,不是吗?但是请你看看下面的代码,他和上面是样的效果:
using namespace std;
using namespace boost::lambda;
extern list<int&> m_list;
int i = 0;
for_each(m_list.begin(), m_list.end(), ( cout << _1, cout << (_1 + i) ) );
也许你和我一样,第一感觉是震惊,“这TMD是怎么回事!?”,但是当你听我解释他工作原理的时候你又会马上发现这一却是多么的自然。因为这个库实在很庞大,所以我只介绍他基本原理,至于代码就不直接讨论。
首先,你必须坚持一点:C++并没有发疯,这完全是符合C++标准的。你会说,“标准!?原始代码都出现在函数参数列表里了,还正常!?”我们知道for_each只接受函数或者仿函数作为他的第三个参数,也就是说( cout << _1, cout << (_1 + i) )返回一个仿函数,但是怎么看也不是一个函数啊,这就是我赞叹作者想象力的地方,你别忘了C++的操作符重载,上面代码实际上重载了operator+, operator<<,operator,。他们都返回一个lambda的仿函数并接受仿函数作为参数。“什么?,也能被重载!?”是的,他可以,只是很少人这么做。lambda的作者重载了所有能重载的操作符,还写了不少判断函数,这就是我佩服他恒心的地方。你又看到了_1,他的作用和bind里的_1的作用大同小异,都是一个占位符。你可以自己去看代码。到这里,你已经不会再为见到下面的代码而吃惊了。
sort(vp.begin(), vp.end(), *_1 > *_2);
for_each(vp.begin(), vp.end(), cout << constant('\n') << *_1);
bool flag = true; int i = 0;
(_1 || ++_2)(flag, i);
struct A { int d; };
A* a = new A();
(_1 ->* &A::d)(a);
struct B { int foo(int); };
B* b = new B();
(_1 ->* &B::foo)(b)(1);
int i = 0; int j;
var_type<int>::type vi(var(i)), vj(var(j));
for_each(a.begin(), a.end(), (vj = _1, _1 = vi, vi = vj));
int a[5][10]; int i;
for_each(a, a+5, for_loop(var(i)=0, var(i)<10, ++var(i), _1[var(i)] += 1));
for_each(a.begin(), a.end(), if(_1 % 2 == 0)[ cout << _1 ])
std::for_each(v.begin(), v.end(),
(
switch_statement
(
_1,
case_statement<0>(std::cout << constant("zero")),
case_statement<1>(std::cout << constant("one")),
default_statement(cout << constant("other: ") << _1)
),
cout << constant("\n")
)
);
还有很多,但是除了极为简单的情况,我们推荐使用以外,其他情况都不推荐,他不仅会在效率上惩罚你,因为有多少个操作符实际上就有多少个函数调用和参数传递,而且根本不能调试,并且还造成复用困难,对不了解lambda的人来说就更是不可理解了。
水平平庸,错误难免,请指正为谢 《解析boost》
|
|