Chinaunix首页 | 论坛 | 博客
  • 博客访问: 148730
  • 博文数量: 54
  • 博客积分: 1732
  • 博客等级: 上尉
  • 技术积分: 520
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-23 23:29
文章分类

全部博文(54)

文章存档

2011年(3)

2010年(26)

2009年(25)

分类: C/C++

2009-11-30 00:33:26

按照我想一出演一出的坏习惯,最近突然心血来潮想要试试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

阅读(1053) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~