Home > Software design >  Cannot iterate through map in print() method
Cannot iterate through map in print() method

Time:01-23

I've done some exercises before where I loop through maps no problem. Now that I'm doing so in a class, I'm getting strange errors that I don't understand at all. It seems to happen at the instantiation of the iterator in the print() method.

error: conversion from ‘std::mapstd::__cxx11::basic_string<char, bool>::const_iterator’ {aka ‘std::_Rb_tree_const_iterator<std::pair<const std::__cxx11::basic_string, bool> >’} to non-scalar type ‘std::mapstd::__cxx11::basic_string<char, bool>::iterator’ {aka ‘std::_Rb_tree_iterator<std::pair<const std::__cxx11::basic_string, bool> >’} requested 33 | for (map<string, bool>::iterator i = jobs.begin(); i != jobs.end(); i ) {

Here is my code:

class Employee {
private:
    string name;
    map<string, bool> jobs;

public:

    Employee() {
        name = "";
        jobs[""] = false;
    }
    
    Employee(const Employee &other) {
        cout << "Copied." << endl;
        name = other.name;
        jobs = other.jobs;
    }

    Employee(string name, string task, bool trained) {
        this->name = name;
        jobs[task] = trained;
    }
    
    void setTask(string task, bool trained) {
        jobs[task] = trained;
    }
    
    void print() const {
        for (map<string, bool>::iterator i = jobs.begin(); i != jobs.end(); i  ) {
            pair<string, bool> jobs = *i;
            cout << name << " is trained on " << jobs.first << "? " << jobs.second << endl;
        }
    }
};

I promise I did my best to look for solutions online before coming here. Sorry if I'm misunderstanding something extremely elementary.

I've tried making the print method const or not const, and I've experimented with using const_iterator and .cbegin()/.cend() in case it was being picky about that. Sadly, I'm just not very good at debugging yet.

CodePudding user response:

void print() const

That const in the end means that this class method is a const class method. It can be called on const instances of this class. What it means is that, as far as this method is concerned, all members of its class are const.

map<string, bool>::iterator i = jobs.begin(); 

Since this is const, the begin() overload returns a const_iterator, instead of iterator, and that's the reason for your compilation error.

I've tried making the print method const or not const,

But what you haven't tried to do is use the current C standard, you are apparently using a very, very outdated textbook to learn C . Current C makes all of this much easier:

   void print() const {
        for (auto &job:jobs)
            cout << name << " is trained on " << job.first << "? " << job.second << endl;
        }

And that's not even the best way to do it. I'll leave it to you to get your textbook updated, and learn about structured bindings that makes this even cleaner to read.

CodePudding user response:

Your print member function is declared as const, so all occurrences/uses of data members of the class made within it will also be treated as const.

Thus, the calls to jobs.begin() and jobs.end() will invoke the const overloads of those functions, which have return types of const_iterator. So, to fix your issue, make i a const_iterator:

    void print() const {
        for (map<string, bool>::const_iterator i = jobs.begin(); i != jobs.end(); i  ) {
            pair<string, bool> localjob = *i; // Avoid "shadowing" member variable!
            cout << name << " is trained on " << localjob.first << "? " << localjob.second << endl;
        }
    }

CodePudding user response:

The member function print is a constant member function. It means that within the function data members of the class are constants. So instead of map<string, bool>::iterator you need to use map<string, bool>::const_iterator

Also it is a bad idea to redeclare the name jobs within the for loop. And moreover this declaration is redundant.

You should write

void print() const {
    for (map<string, bool>::const_iterator i = jobs.cbegin(); i != jobs.cend(); i  ) {
        cout << name << " is trained on " << i->first << "? " << i->second << endl;
    }
}

If your compiler supports C 17 then you could use range-based for loop the following way

void print() const {
    for ( const auto &[first, second] : jobs ) {
        cout << name << " is trained on " << first << "? " << second << endl;
    }
}
  • Related