使用for_each修改标准容器(即使您不应该这样做) [英] Using for_each to modify std containers (even though you shouldn't)
问题描述
我正在学习C ++自学课程,学习标准库的工作方式,并且我想了解使用 for_each
的代码的工作方式,尤其是关于使 objects (与本机数据类型相反).我意识到您不应使用 for_each
这种方式,但这是为了学习的目的.
I'm taking a self-study course for C++, learning how the Standard Library works, and I want to understand how this code that uses for_each
works, particularly regarding mutating objects (as opposed to native data types). I realize that you shouldn't use for_each
this way, but this is for the purpose of learning.
我曾经以为这段代码会改变集合中的所有元素,但事实并非如此.
I had thought this code would mutate all the elements in the set, but it doesn't.
我的问题是:1.此代码为什么不更改集合?2.如何更改代码,以便将修改集合?需要说明的是:是否有一种方法可以保留 for_each
并让它操纵该集合,还是不可能的,因此必须使用其他方法(例如 transform
)?
My question is: 1. Why doesn't this code mutate the set?
2. How can the code be altered so that it will modify the set? To clarify: is there a way to keep the for_each
and have it manipulate the set, or is this not possible and some other method (such as transform
) has to be used?
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
class A {
int a;
public:
A(int a) : a(a) {}
int getA() const { return a; }
void setA(int a) { this->a = a; }
bool operator<(const A & b) const { return a<b.a; }
};
struct myprinter {
void operator()(const A & a) { cout << a.getA() << ", "; }
};
struct doubler {
void operator()(A a) { a.setA(a.getA()*2); }
};
int main() {
int mynumbers[] = {8, 9, 7, 6, 4, 1};
set<A> s1(mynumbers, mynumbers+6);
for_each(s1.begin(), s1.end(), doubler()); //<-- Line in question
for_each(s1.begin(), s1.end(), myprinter());
return 0;
}
//Expected output: 2, 8, 12, 14, 16, 18
//Actual output: 1, 4, 6, 7, 8, 9,
到目前为止我已经尝试过的
-
起初,我认为问题在于doubler是通过值而不是通过引用来获取参数,因此它没有将更改保存到集合中.但是,当我将签名更改为
void operator()(A& a)
时,出现以下错误:error: no match for call to '(doubler) (const A&) ' __f(*__first); ~~~^~~~~~~~~~ error: binding 'const A' to reference of type 'A&' discards qualifiers
我推断指出的那行是来自
for_each
的内部实现.我无法将参数设为const ref,因为我正尝试使用setA()
方法更改a
值,因此不能为const
.I deducted that that line being pointed out is from the internal implementation of
for_each
. I cannot make the parameter a const ref, because I am trying to change thea
value using thesetA()
method, so it cannot beconst
.编辑:moooeeeep链接到另一个问题,该问题显示了如何编辑集合中的每个元素.这是解决我的问题的一种实用方法,但是我的问题是理论上更多的-为什么不能使用
for_each
来编辑集合,而在其中可以编辑矢量和其他stl容器?moooeeeep linked to another question that shows how to edit each element of a set. This is a practical solution to my problem, but my question is more theoretical - why can you not edit sets using
for_each
, where you can edit vectors and other stl containers?推荐答案
由于
std :: set
管理其元素的顺序,因此禁止用户通过其迭代器更改其元素.这意味着它是begin()
和end()
方法返回const_iterator
.您只能读取该迭代器指向的元素,而不能修改doubler()
试图做的事情(它是const).Because a
std::set
manages the order of it's elements, it prohibits the user to change it's elements through it's iterators. Which means it'sbegin()
andend()
methods return aconst_iterator
. You're only allowed to read the element pointed to by that iterator, not modify it (it's const) which is whatdoubler()
is trying to do.解决方案是仅使用
std :: vector
和std :: sort
自己订购:A solution would be to just use
std::vector
andstd::sort
to order it yourself:#include <iostream> #include <algorithm> #include <vector> class A { int a; public: A(int a) : a(a) {} int getA() const { return a; } void setA(int a) { this->a = a; } bool operator<(const A & b) const { return a<b.a; } }; struct myprinter { void operator()(const A & a) { cout << a.getA() << ", "; } }; struct doubler { void operator()(A& a) { a.setA(a.getA()*2); } // by reference! }; int main() { int mynumbers[] = {8, 9, 7, 6, 4, 1}; std::vector<A> s1(mynumbers, mynumbers+6); std::sort(s1.begin(), s1.end()); std::for_each(s1.begin(), s1.end(), doubler()); std::for_each(s1.begin(), s1.end(), myprinter()); return 0; }
这篇关于使用for_each修改标准容器(即使您不应该这样做)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!