按照我想一出演一出的坏习惯,最近突然心血来潮想要试试c++0x支持的lambda函数,于是乎跑到Bjarne Stroustrup 他老人家的博客上找到了c++0x的链接,翻到lambda函数的部分:
~bs/C++0xFAQ.html#lambda
看完之后,觉得可以动手了(我现在可没兴趣对着那个草案标准把lambda函数相关的部分研读一遍先,还是老老实实先啃完《TC++PL》吧),想起前一阵在水木上看到某大拿对一笔试题的解法,觉得拿来练习lambda函数那是相当的合适:
输入:某整数集合
输出:将所有的奇数排到数组前面,并为升序;所有的偶数排到数组后面,并为降序
要求不能开辟新的临时内存空间
我本人看到这个题的第一反应就是用两轮循环,首先将奇数置于前面,偶数置于后面,然后用快排(调用std::sort()即可
然而有大拿告诉我,其实这跟一个最基本的排序算法一样的,所不同的是比较函数定义不同而已,我们可以这样定义一个比较函数:
template <typename _Data>
inline bool comp(_Data n1, _Data n2)
{
if( (n2 % 2) == (n1 % 2))
return ( ((n1%2)==1) && (n1<n2) ) /* 对于奇数来说,按照"<"排序 */
|| ( ((n1%2)==0) && (n2<n1) ); /* 对于偶数来说,按照">"排序 */
else
return (n2 % 2) < (n1 % 2); /* 如果奇偶不同,则定义所有的奇数都小于偶数*/
}
|
为了使该比较函数对于所有的整数(int, short, long等)都适应,我将其定义成了模板。
首先是普通函数版本,即不使用lambda函数,以下是我的第一个main函数:int main(int argc, char *argv[])
{
std::vector<int> iVec;
std::istream_iterator<int> iIter(std::cin);
std::istream_iterator<int> eof;
/* read data from the std input */
std::copy( iIter, eof,
std::back_inserter(iVec) );
/* I haven't consider the status of the input stream */
std::sort(iVec.begin(), iVec.end(),
comp);
/* output the data */
int n=0;
for(std::vector<int>::const_iterator iter= iVec.begin();
iter != iVec.end();
++iter)
{
std::cout<< std::setw(10) << std::right /* set format */
<<*iter;
if(10==++n)
{
std::cout<<std::endl;
n=0;
}
}
std::cout<<std::endl;
return EXIT_SUCCESS;
}
|
很不幸,上面的代码在编译时报错(还好这个错误不像传说中STL报错信息那么变态):
error: no matching function for call to ‘sort(__gnu_cxx::__normal_iterator > >, __gnu_cxx::__normal_iterator > >, )’
看了一下,大概意思似乎是找不到匹配的sort函数,怎么会呢?恩,后来注意到后面的“unresolved overloaded function type”,不知道comp是什么类型,直接指明其是comp行不?果然,将 std::sort(iVec.begin(), iVec.end(),
comp);
改为 std::sort(iVec.begin(), iVec.end(),
comp);
之后,一切OK,看起来很完美:$ g++ -Wall main.cc
$ rand | ./a.out
3 13 29 43 65 93 147 155 185 215
245 253 255 281 285 303 303 331 331 349
389 389 423 487 489 491 505 517 521 533
561 569 615 619 623 627 629 637 673 677
729 731 765 769 775 797 805 827 835 855
857 867 871 921 923 941 949 965 990 990
962 906 890 886 870 850 830 814 734 716
672 658 620 618 606 538 538 502 440 418
404 394 394 392 352 340 314 276 258 248
232 208 206 204 182 138 56 52 42 0
$ ./a.out
<----这里我直接输入ctrl-D
$
其中rand是我自己写的一个随机数产生器,默认产生100个10到1000范围内的整数,上面的测试说明上面的程序对于空集也能正确的处理
好了,下面开始用lambda函数实现,很简单,去掉comp函数定义,将sort函数调用改为:
std::sort(iVec.begin(), iVec.end(),
[](int n1, int n2)
{
if( (n2 % 2) == (n1 % 2))
return ( ((n1%2)==1) && (n1<n2) )
|| ( ((n1%2)==0) && (n2<n1) );
else
return (n2 % 2) < (n1 % 2);
}
);
|
美观起见,把注释都删除了,对比这里与上面的sort函数,就可以知道lambda函数包括以下几部分:
(1)用圆括号()括起来的参数列表:与普通的函数参数列表无异;
(2)capture list(这个不知道怎么翻译):也就是[]括起来的部分。因为lambda函数可以通过引用访问它本身所在域内的局部变量,这个capture list就用来指示lambda函数可以访问的外围域变量列表(通过传引用的方式),也就是说,对于[]内指示的变量名,lambda函数内可以直接访问并修改其值,且修改后的值长期有效(即传引用而不是传值)。如果是[&]表示lambda函数可以通过引用的方式访问外围域中的所有变量,如果 lambda不需要访问任何外围变量,直接使用[]即可,如同上面的sort所做的一样,下面是另一个lambda函数举例:
void f(vector& v)
{
vector indices(v.size());
int count = 0;
fill(indices.begin(),indices.end(),
[&count](){ return ++count; }
);
|
(3)用花括号{}括住的函数体,与普通函数体无异
一切准备就绪之后,使用g++编译,发现竟然不认识……郁闷的google查询之,然后郁闷的发现g++4.4不支持lambda函数:
神哪,为什么我要犯贱把以前装好gcc4.5的系统完整干净的卸载,看来只能好好练习《TC++PL》上c++98的例子了,现在暂时还没兴趣再编译安装一边gcc
阅读(1070) | 评论(0) | 转发(0) |