C ++ STL - 遍历序列中的所有内容

时间:2009-09-26 03:53:36

标签: c++ stl

我有一个序列,例如

std::vector< Foo > someVariable;

我想要一个遍历其中所有内容的循环。

我可以这样做:

for (int i=0;i<someVariable.size();i++) {
    blah(someVariable[i].x,someVariable[i].y);
    woop(someVariable[i].z);
}

或者我可以这样做:

for (std::vector< Foo >::iterator i=someVariable.begin(); i!=someVariable.end(); i++) {
    blah(i->x,i->y);
    woop(i->z);
}

这些似乎都涉及相当多的重复/过度打字。在理想的语言中,我希望能够做到这样的事情:

for (i in someVariable) {
    blah(i->x,i->y);
    woop(i->z);
}

似乎迭代顺序中的所有内容将是一个非常常见的操作。有没有办法做到这一点,代码不应该是它应该的两倍?

6 个答案:

答案 0 :(得分:12)

您可以使用标准库中的for_each。您可以将仿函数或函数传递给它。我喜欢的解决方案是BOOST_FOREACH,就像其他语言中的foreach一样。 C + 0x会有一个顺便说一句。

例如:

#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/foreach.hpp>

#define foreach BOOST_FOREACH 

void print(int v)
{
    std::cout << v << std::endl;
}

int main()
{
    std::vector<int> array;

    for(int i = 0; i < 100; ++i)
    {
        array.push_back(i);
    }

    std::for_each(array.begin(), array.end(), print); // using STL

    foreach(int v, array) // using Boost
    {
        std::cout << v << std::endl;
    }
}

答案 1 :(得分:5)

不计算AraK已经建议的BOOST_FOREACH,你今天在C ++中有以下两个选项:

void function(Foo& arg){
  blah(arg.x, arg.y);
  woop(arg.z);
}

std::for_each(someVariable.begin(), someVariable.end(), function); 

struct functor {
  void operator()(Foo& arg){
    blah(arg.x, arg.y);
    woop(arg.z);
  }
};

std::for_each(someVariable.begin(), someVariable.end(), functor());

两者都要求你在别处指定循环的“body”,作为函数或函数(一个重载operator()的类)。那个可能是一件好事(如果你需要在多个循环中做同样的事情,你只需要定义一次这个函数),但它也可能有点乏味。函数版本的效率可能稍低,因为编译器通常无法内联函数调用。 (函数指针作为第三个参数传递,编译器必须进行更详细的分析以确定它指向哪个函数)

仿函数版本基本上是零开销。因为functor类型的对象被传递给for_each,所以编译器确切地知道要调用哪个函数:functor::operator(),因此它可以简单地内联并且与原始函数一样有效。循环。

C ++ 0x将引入lambda表达式,使第三种形式成为可能。

std::for_each(someVariable.begin(), someVariable.end(), [](Foo& arg){
  blah(arg.x, arg.y);
  woop(arg.z);
});

最后,它还将引入基于范围的for循环:

for(Foo& arg : my_someVariable)
{
  blah(arg.x, arg.y);
  woop(arg.z);
}

因此,如果您可以访问支持C ++ 0x子集的编译器,则可以使用其中一个或两个最后一个表单。否则,惯用解决方案(不使用Boost)就像在前两个示例之一中使用for_each一样。

答案 2 :(得分:1)

首选算法调用手写循环

有三个原因:

1)效率:算法通常比程序员生成的循环更有效

2)正确性:写入循环比调用算法更容易出错。

3)可维护性:算法调用通常会产生更清晰且更多的代码    直接比相应的显式循环。

答案 3 :(得分:1)

顺便说一句,MSVS 2008有一个“for each”C ++关键字。请看How to: Iterate Over STL Collection with for each

int main() {
   int retval = 0;

   vector<int> col(3);
   col[0] = 10;
   col[1] = 20;
   col[2] = 30;

   for each( const int& c in col )
      retval += c;

   cout << "retval: " << retval << endl;
}

答案 4 :(得分:0)

几乎所有其他算法都倾向于for_each()

有两个原因:

  1. for_each非常一般,不会告诉你什么是真正做的,只是你正在对序列中的所有项目做些什么。
  2. 更专业的算法通常更简单,更直接

考虑一下先前回复中的一个例子:

void print(int v)
{
    std::cout << v << std::endl;
}
// ...
std::for_each(array.begin(), array.end(), print); // using STL

使用std :: copy代替,整个事情变成:

std :: copy(array.begin(),array.end(),std :: ostream_iterator(std :: cout,“\ n”));

答案 5 :(得分:0)

"struct functor {
  void operator()(Foo& arg){
    blah(arg.x, arg.y);
    woop(arg.z);
  }
};

std::for_each(someVariable.begin(), someVariable.end(), functor());"

我认为像这样的方法通常是不必要的巴洛克式的简单问题。

do i=1,N
 call blah( X(i),Y(i) )
 call woop( Z(i) )
end do

非常清楚,即使它已经40岁了(显然不是C ++)。

如果容器总是一个向量(STL名称),我看到索引没有错,并且将该索引称为整数没有错。

在实践中,通常需要同时迭代多个相同大小的容器并从每个容器中剥离一个数据,然后对它们进行一些处理。在那种情况下,尤其是为什么不使用索引?

就SSS的第2点和第3点而言,我认为对于复杂的情况可能是这样,但经常迭代1 ... N通常与其他任何事情一样简单明了。

如果您必须在白板上解释算法,是否可以使用“我”或不使用“我”更快地完成此操作?我想如果您的meatspace解释更清楚,请在代码空间中使用它。

为强硬目标保存沉重的C ++火力。