使用C ++中的std :: for_each的Functor

时间:2016-02-27 01:30:24

标签: c++ functor

这是我从http://www.catonmat.net/blog/on-functors/复制的仿函数代码。

#include <algorithm>
#include <iostream>
#include <list>

class EvenOddFunctor {
    int even_;
    int odd_;
public:
    EvenOddFunctor() : even_(0), odd_(0) {}
    void operator()(int x) {
        if (x%2 == 0) even_ += x;
        else odd_ += x;
    }
    int even_sum() const { return even_; }
    int odd_sum() const { return odd_; }
};

int main() {
    EvenOddFunctor evenodd;

    int my_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    // ??? why assign 
    evenodd = std::for_each(my_list,
                  my_list+sizeof(my_list)/sizeof(my_list[0]),
                  evenodd); // ???

    std::cout << "Sum of evens: " << evenodd.even_sum() << "\n";
    std::cout << "Sum of odds: " << evenodd.odd_sum() << std::endl;

    // output:
    // Sum of evens: 30
    // Sum of odds: 25
}

为什么我们需要在操作后将值赋回evanodd对象,如evenodd = std::for_each(my_list,?我认为,当从std :: for_each更新evenodd对象时,我不需要赋值操作,但是没有这个赋值,结果显示为0.

2 个答案:

答案 0 :(得分:3)

std::for_each按值接受仿函数,这意味着它会修改本地副本。该作业将获得该本地副本,以便您可以实际看到修改后的版本。

这很重要,因为您的仿函数具有您感兴趣的可变状态,尤其是evenodd.even_sumevenodd.odd_sum

答案 1 :(得分:3)

我们做一些实验。

首先,尽量不要分配它,看看会发生什么。在你尝试之后,如果你弄明白了,就没有必要再读一遍,所以你可以停下来。

如果您无法弄清楚,让我们进行第二次实验,并按如下方式更改main()的相关部分:

const EvenOddFunctor evenodd_orig;

int my_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// ??? why assign
auto evenodd = std::for_each(my_list,
              my_list+sizeof(my_list)/sizeof(my_list[0]),
              evenodd_orig); // ???

这里的关键部分是您将常量对象传递给std::for_each。这将编译,但如果std::for_each按照思考的方式工作,则不应编译。

毕竟,operator() 不是一个常量方法,所以std::for_each得到一个const引用,它应该不能调用你的mutable {{1方法。

那是因为实际发生的事情是operator()制作了你传递给它的仿函数的内部副本。它通过值而不是引用来获取其仿函数参数,并且您的仿函数最终会修改其内部状态。

这就是为什么std::for_each在完成后返回仿函数对象的原因,这就是你需要存储它的原因,因为传递给std::for_each的原始对象尚未被修改!