C++ 中带有 std::for_each 的函子
Functor with std::for_each in C++
这是我从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。
std::for_each
按值接受仿函数,这意味着它修改本地副本。该作业会取回该本地副本,因此您实际上可以看到修改后的版本。
这很重要,因为您的仿函数具有您感兴趣的可变状态,特别是 evenodd.even_sum
和 evenodd.odd_sum
。
让我们做几个实验。
首先,尽量不要赋值,看看会发生什么。试过之后,如果你想通了,就不用再看了,你可以停下来。
如果你想不通,我们再做一次实验,将你的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
得到一个常量引用,它不应该能够调用你的可变 operator()
方法。
那是因为本质上发生的事情是 std::for_each
制作了您传递给它的仿函数的内部副本。它通过值而不是通过引用获取其仿函数参数,并且您的仿函数最终会修改其内部状态。
这就是为什么 std::for_each
returns 仿函数对象完成后,这就是为什么你需要存储它,因为传递给 std::for_each
的原始对象还没有已修改!
这是我从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。
std::for_each
按值接受仿函数,这意味着它修改本地副本。该作业会取回该本地副本,因此您实际上可以看到修改后的版本。
这很重要,因为您的仿函数具有您感兴趣的可变状态,特别是 evenodd.even_sum
和 evenodd.odd_sum
。
让我们做几个实验。
首先,尽量不要赋值,看看会发生什么。试过之后,如果你想通了,就不用再看了,你可以停下来。
如果你想不通,我们再做一次实验,将你的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
得到一个常量引用,它不应该能够调用你的可变 operator()
方法。
那是因为本质上发生的事情是 std::for_each
制作了您传递给它的仿函数的内部副本。它通过值而不是通过引用获取其仿函数参数,并且您的仿函数最终会修改其内部状态。
这就是为什么 std::for_each
returns 仿函数对象完成后,这就是为什么你需要存储它,因为传递给 std::for_each
的原始对象还没有已修改!