C ++中的foreach算法

时间:2009-11-25 20:28:24

标签: c++

有没有办法从我传递给foreach的函数中获得返回值。

对于前: 我有,

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

vector<int> myvector;
myvector.push_back(10);
for_each (myvector.begin(), myvector.end(), myfunction);

让我们说,我想使用一些规则计算向量中的元素数量,我想从myFunction获得返回值,这可能吗?

10 个答案:

答案 0 :(得分:13)

有一个特殊目的std::count(值的计数出现)和std::count_if(谓词返回true时计数)。不要将std::for_each滥用于不适合的内容。

答案 1 :(得分:9)

for_each将返回您传递的仿函数的副本。这意味着你可以这样做:

template <typename T>
class has_value
{
    has_value(const T& pValue) : mValue(pValue), mFlag(false) {}

    void operator()(const T& pX)
    {
        if (pX == mValue)
            mFlag = true;
    }

    operator bool(void) const { return mFlag; }
private:
    T mValue;
    bool mFlag;
};

bool has_seven = std::for_each(myvector.begin(), myvector.end(), has_value<int>(7));

例如。但是对于计数等,请查看algorithm并查看您的功能是否已存在。 (如count

答案 2 :(得分:5)

没有。但是你可以使myfunction成为一个仿函数,将指针传递给某个内存,并通过该指针存储你的返回值。

struct MyFunctor {
    int *count;
    MyFunctor(int *count_) : count(count_) { }
    void operator()(int n) {
        if (n > 5) (*count)++;
    }
};

int main() {
    vector<int> vec;
    for (int i=0; i<10; i++) vec.push_back(i);
    int count = 0;
    for_each(vec.begin(), vec.end(), Myfunctor(&count));
    printf("%d\n", count);
    return 0;
}

编辑:正如评论所指出的那样,我的第一个例子会失败,因为for_each会复制MyFunctor,所以我们不能拥有从原始对象中检索返回值。我已经修改了原来的方法;但你真的应该看看更加优雅的GMan解决方案。我不确定可移植性,但它确实适用于我的gcc(4.4.2)。正如其他人提到的那样,尽可能使用<algorithm>提供的内容。

答案 3 :(得分:3)

如果你想要强大的foreach,那就是BOOST_FOREACH makro。此外,boost主要是头库,因此您只能将boost_foreach.hpp(afair)包含在项目中。例如:

BOOST_FOREACH( int & i , my_vector )
{
     i = 0;
}

My_vector可以是vector<int>int[]或任何其他类型的迭代器。

答案 4 :(得分:2)

这不是functors的用途吗?

答案 5 :(得分:1)

std::for_each并非专为此而设计。使用std::count计算等于某个值的元素数,或std::count_if计算满足某些谓词的元素:

std::vector<SomeType> vec;
std::count(vec.begin(), vec.end(), SomeType(9));
/*or */
bool myfunc(const SomeType& v)
{
    return v == 9;
}
std::count_if(vec.begin(), vec.end(), f);

如果您只想将容器的内容复制到像std::cout这样的ostream对象,请改用std :: copy:

std::vector<SomeType> vec;
...
std::copy(vec.begin(), vec.end(), \
    std::ostream_iterator<SomeType>(std::cout," "));

如果需要每次调用函数的返回值,请使用std::transform

std::vector<SomeType> src;
std::vector<SomeType> result;
int myfunc(int val)
{
    ...
}
std::transform(src.begin(), src.end() \
    result.begin(), myfunc);

std::transform也被重载,因此它适用于二进制函数和一元函数。

答案 6 :(得分:1)

好吧,我担心你在选择计数问题时选择了你的例子......

问题在于for_each非常通用,并且针对特定实施存在更具体的算法(countaccumulatetransform,...)

让我们再举一个例子:for_each通常用于对它所对待的对象应用变异操作。它不会阻止您在执行此操作时收集统计信息。

我们必须小心,虽然for_each确实返回Predicate对象,但无法保证此对象在范围内的每个项目上都使用。该实现可以自由地复制谓词并在部分范围内使用副本...所以你最终返回的副本可能是不受欢迎的。

class Predicate
{
public:
  Predicate(size_t& errors) : m_errors(errors) {}
  void operator()(MyObject& o)
  {
    try { /* complicated */ } catch(unfit&) { ++m_errors; }
  }
private:
  size_t& m_errors;
};

std::vector<MyObject> myVec;
// fill myVec

size_t errors = 0;
std::for_each(myVec.begin(), myVec.end(), Predicate(errors));

这里的技巧是原始谓词的所有副本都将指向相同的size_t变量,因此该变量已被正确更新。

答案 7 :(得分:1)

可以改编std::for_each来做这件事,就像GMan所说的那样。

但更好的解决方案是使用正确的算法。

您应该能够使用std::countstd::count_if,或者std::accumulate。 这些允许您返回一个结果来处理整个序列。

或者std::transform允许您返回序列中每个元素的结果,创建一个包含结果的新输出序列。

答案 8 :(得分:0)

看看<algorithm>

我认为std::count_if是您正在寻找的。

答案 9 :(得分:0)

这是可行的:

int main()
{
  std::vector<int> v;
  for (int i = 1; i <= 10; i++)
    v.push_back(i);

  int hits = 0;
  CountEven evens(&hits);
  std::for_each(v.begin(), v.end(), evens);
  std::cout << "hits = " << hits << std::endl;

  return 0;
}

但请看一下CountEvens的讨厌的实现:

class CountEven {
  public:
  CountEven(int *hits) : hits(hits) {}
  CountEven(const CountEven &rhs) : hits(rhs.hits) {}
  void operator() (int n) { if (n % 2 == 0) ++*hits; }

  private:
  int *hits;
};

请注意,复制构造函数会导致多个实例共享同一个指针。

使用std::countstd::count_if