【问题标题】:Functor with std::for_each in C++C++ 中带有 std::for_each 的函子
【发布时间】:2016-02-27 01:30:24
【问题描述】:

这是我从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
}

为什么我们需要像evenodd = std::for_each(my_list,一样在操作后将值赋回evanodd对象?我以为由于evenodd对象是从std::for_each更新的,所以不需要赋值操作,但是没有这个赋值,结果显示为0。

【问题讨论】:

    标签: c++ functor


    【解决方案1】:

    std::for_each 按值接受函子,这意味着它修改了本地副本。分配会取回该本地副本,因此您可以实际查看修改后的版本。

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

    【讨论】:

      【解决方案2】:

      让我们做一些实验。

      首先,尽量不要分配它,看看会发生什么。试过之后,如果你想通了,就不用再看下去了,你可以停下来。

      如果看不出来,我们再做个实验,把你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); // ???
      

      这里的关键部分是您将 constant 对象传递给std::for_each。这将编译,但如果 std::for_each 以您认为的方式工作,则不应编译。

      毕竟,operator()不是一个常量方法,所以std::for_each 获得一个常量引用,它应该不能调用你的可变operator() 方法。 p>

      这是因为本质上发生的是std::for_each 制作了您传递给它的函子的内部副本。它通过值而不是引用来获取其仿函数参数,并且您的仿函数最终会修改其内部状态。

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

      【讨论】:

        猜你喜欢
        • 2010-09-18
        • 1970-01-01
        • 2011-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多