最后更新于 .

python,c#,java里面都有类似于foreach的结构,stl里面虽然有for_each这个函数,但是感觉使用还是太繁琐了一些,所以就自己实现了一个。 先来看看stl里面的for_each函数,官方文档上的原型如下:

Function for_each (InputIterator first, InputIterator last, Function f);

示例代码如下:

// for_each example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

void myfunction (int i) {
  cout << " " << i;
}

struct myclass {
  void operator() (int i) {cout << " " << i;}
} myobject;

int main () {
  vector<int> myvector;
  myvector.push_back(10);
  myvector.push_back(20);
  myvector.push_back(30);

  cout << "myvector contains:";
  for_each (myvector.begin(), myvector.end(), myfunction);

  // or:
  cout << "\nmyvector contains:";
  for_each (myvector.begin(), myvector.end(), myobject);

  cout << endl;

  return 0;
}

不只函数原型有点不习惯,而且还要再写一个函数,比起python的实现方式,的确有点繁琐了:

for d in l:
    print d

我们来自己实现一个,方法肯定是用宏啦,我们来看一下第一个版本:

#define foreach(container,it,type) \
    for(type::iterator it = (container).begin();it!=(container).end();++it)

示例代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
using namespace std;

#define foreach(container,it,type) \
    for(type::iterator it = (container).begin();it!=(container).end();++it)

int main(int argc, const char *argv[])
{
    set<string> s;
    s.insert("w");
    s.insert("a");
    s.insert("n");


    foreach(s,it,set<string>)
    {
        cout<<*it<<endl;
    }

    /*map<unsigned,string> m;
    m[0]="x";
    m[1]="w";

    foreach(m,it,map<unsigned,string>)
    {
        cout<<it->first<<","<<it->second<<endl;
    }*/

    return 0;
}

如果把注释掉的代码打开的话,就会报错,应该是宏无法处理逗号的原因。 而且调用起来还是有点繁琐对吧,python里面并没有要求传入容器类型,我们是不是也能把set这个参数省掉呢? 先来看一下这段代码:

typeof(10) a;
a = 100;
cout<<a<<endl;

这段代码是可以执行的,运行结果是100。从这一点出发,我们是不是能通过typeof(container)获得容器类型,然后通过typeof(container)::iterator创建遍历指针呢,我们来看第二个版本

#define foreach(container,it) \
    for(typeof(container)::iterator it = (container).begin();it!=(container).end();++it)

然而很不幸,这段代码是无法运行的,编译结果如下:

test4.cpp|21| error: expected initializer before "it"
test4.cpp|21| error: `it' was not declared in this scope
test4.cpp|34| error: expected initializer before "it"
test4.cpp|34| error: `it' was not declared in this scope

有没有办法解决呢?
有的,我们用一个曲线救国的方法!typeof(container.begin()) ,哈哈!最终代码如下:

#define foreach(container,it) \
    for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it)

测试代码如下:

#include <vector>
#include <set>
#include <map>
using namespace std;

#define foreach(container,it) \
    for(typeof((container).begin()) it = (container).begin();it!=(container).end();++it)

int main(int argc, const char *argv[])
{
    set<string> s;
    s.insert("w");
    s.insert("a");
    s.insert("n");


    foreach(s,it)
    {
        cout<<*it<<endl;
    }

    map<unsigned,string> m;
    m[0]="x";
    m[1]="w";

    foreach(m,it)
    {
        cout<<it->first<<","<<it->second<<endl;
    }

    return 0;
}

输入结果如下:

a
n
w
0,x
1,w

OK!一切正常!这应该是形式比较简单的版本啦,如果各位有什么更好的建议,欢迎留言交流~
ps:
当然,其实你连it这个参数都可以省掉,但是根据pythonic的原则(好吧,我知道自己是在写C++),要简单但不能让人迷惑,所以建议还是把it这个参数保留。

Pingbacks

Pingbacks已打开。

Trackbacks

引用地址

评论

  1. 依云

    依云 on #

    很不错呵。不知道在Java里有没有办法实现呢。

    Reply

  2. 果然如此

    果然如此 on #

    ……对foreach这种“冗余”向来无爱。。。。。。

    Reply

  3. 鸿志

    鸿志 on #

    typeof是不是只是gcc扩展,vc2005是没有的?

    Reply

    1. Dante

      Dante on #

      呃,不用vs很久了。。。
      这个我也不太清楚哦。。。可以写写试试。。

      Reply

      1. 鸿志

        鸿志 on #

        试了一下,不行,杯具。不知道有什么可以替代typeof的。。。。。

        Reply

        1. Dante

          Dante on #

          呃,那我就真的不知道了。。。

          Reply

  4. 吴亮

    吴亮 on #

    boost中有一个BOOSY_FOREACH和楼主实现的功能基本一致,呵呵

    Reply

    1. Dante

      Dante on #

      哈,找时间看一下~~一直没有机会去看一下boost库的实现~

      Reply

  5. sw

    sw on #

    这个貌似是MS的扩展。在C++0x里面有declType是跟这个意义相同的。

    另外,貌似C++0x支持lambda,写起来会简单。

    最后,不知道C++0x有没有提供内建的 foreach…………

    Reply

    1. Dante

      Dante on #

      我是在gcc编译的哦,不用MS很多年了。。。
      没有用过C++0x,这篇文章纯属个人偷懒之用,哈。。

      Reply

  6. alex

    alex on #

    提个建议,宏用大写,否则小心别人用这个当函数名,结果报莫名其妙的错误。

    Reply

  7. reezhou

    reezhou on #

    新版c++标准 最好使用decltype

    Reply

  8. darkcat

    darkcat on #

    c++11里有typeof和auto,可以这样写:

    // C++98
    for( vector::iterator i = v.begin(); i != v.end(); ++i ) {
    total += *i;
    }

    // C++11
    for( auto d : v ) {
    total += d;
    }

    Reply

  9. 123

    123 on #

    为什么不用auto呢

    Reply

    1. Dante

      Dante on #

      好多好多好多年前的代码了。。。

      Reply

  10. missmary

    missmary on #

    不错,不过每次都要对it解引用还是有点麻烦的,有时候也容易忘。稍微改了下:#define foreach(c,el) typeof(*(c).begin()) el; for ( typeof((c).begin()) _it_ = (c).begin(); (_it_ != (c).end()) &amp;&amp; ((el = *_it_) || true); _it_++ )使用方法:vector list;list.push_back("abc"); list.push_back("efg");foreach(list, el) cout&lt;

    Reply

  11. missmary

    missmary on #

    使用方法:vector list;list.push_back("abc"); list.push_back("efg");foreach(list, el) cout&lt;

    Reply

  12. hugoyu

    hugoyu on #

    可以参看一下C++11以来的Range-based for loop :
    http://en.cppreference.com/w/cpp/language/range-for

    Reply

发表评论