使用for_each修改标准容器(即使您不应该这样做) [英] Using for_each to modify std containers (even though you shouldn't)

查看:62
本文介绍了使用for_each修改标准容器(即使您不应该这样做)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习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 the a value using the setA() method, so it cannot be const.

    编辑: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's begin() and end() methods return a const_iterator. You're only allowed to read the element pointed to by that iterator, not modify it (it's const) which is what doubler() is trying to do.

    解决方案是仅使用 std :: vector std :: sort 自己订购:

    A solution would be to just use std::vector and std::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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆