我正在学习 C++ 的自学课程,学习标准库的工作原理,我想了解这段代码是如何for_each工作的,特别是关于变异对象(与本机数据类型相反)。我意识到你不应该使用for_each这种方式,但这是为了学习。
我原以为这段代码会改变集合中的所有元素,但事实并非如此。
我的问题是: 1. 为什么这段代码不会改变集合?2.如何代码被修改,以便它会修改的设置?澄清一下:有没有办法保留for_each并让它操纵集合,或者这是不可能的并且transform必须使用其他一些方法(例如)?
#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,
Run Code Online (Sandbox Code Playgroud)
起初我认为问题在于 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
Run Code Online (Sandbox Code Playgroud)
我推断指出的那条线是从for_each. 我不能使参数成为 const ref,因为我试图a使用该setA()方法更改值,因此它不能是const.
编辑: moooeeeeep 链接到另一个问题,该问题显示了如何编辑 set 的每个元素。这是我的问题的实用解决方案,但我的问题更具理论性 -为什么不能使用 编辑集合for_each,您可以在其中编辑向量和其他 stl 容器?
因为 astd::set管理其元素的顺序,所以它禁止用户通过它的迭代器更改它的元素。这意味着它begin()和end()方法返回 a const_iterator。您只能读取该迭代器指向的元素,而不能修改它(它是 const),而这正是我们doubler()想要做的。
一个解决方案是自己使用std::vector和std::sort订购它:
#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;
}
Run Code Online (Sandbox Code Playgroud)