Overloading insertion operator with map

Hi,

This is my code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef PHONEBOOK_H
#define	PHONEBOOK_H

#include <map>
#include <string>
#include <utility>
#include <ostream>
#include "Abonent.h"

class PhoneBook {
public:
    void addAbonent(const Abonent& abonent);
    void delAbonent(const Abonent& abonent);
    friend std::ostream& operator<<(std::ostream& stream, const PhoneBook& a);
private:
    std::map<std::string, std::string> base;
    std::map<std::string, std::string>::iterator it;
};

inline std::ostream& operator<<(std::ostream& stream, const PhoneBook& pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}

#endif	/* PHONEBOOK_H */ 


The problem string is:

 
for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {


Output:
error: no match for 'operator=' in 'pb.PhoneBook::it = pb.PhoneBook::base.std::map<_Key, _Tp, _Compare, _Alloc>::begin [with _Key = std::basic_string<char>, _Tp = std::basic_string<char>, _Compare = std::less<std::basic_string<char> >, _Alloc = std::allocator<std::pair<const std::basic_string<char>, std::basic_string<char> > >, std::map<_Key, _Tp, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >]()'


Thank you!
Last edited on
I think you need to use a const_iterator since you are dealing with a const PhoneBook. I'd probably make the iterator inside the for loop instead of having it be a member of the class.
Thank you!

> I think you need to use a const_iterator since you are dealing with a const PhoneBook
How I will be increase it? ++(pb.it)

> I'd probably make the iterator inside the for loop instead of having it be a member of the class.
I use the iterator yet in the function:
1
2
3
4
void PhoneBook::delAbonent(const Abonent& abonent) {
    this->it = this->base.find(abonent.getName());
    this->base.erase(it);
}


Maybe (it works):
 
friend std::ostream& operator<<(std::ostream& stream, PhoneBook a);

1
2
3
4
5
6
inline std::ostream& operator<<(std::ostream& stream, PhoneBook pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}
Last edited on
But I want to use:
 
const PhoneBook& a


Or must I use?
PhoneBook a

Sorry for my English.
Last edited on
> How I will be increase it? ++(pb.it)
Sorry. I can increase it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef PHONEBOOK_H
#define	PHONEBOOK_H

#include <map>
#include <string>
#include <utility>
#include <ostream>
#include "Abonent.h"

class PhoneBook {
public:
    void addAbonent(const Abonent& abonent);
    void delAbonent(const Abonent& abonent);
    friend std::ostream& operator<<(std::ostream& stream, const PhoneBook& a);
private:
    std::map<std::string, std::string> base;
    std::map<std::string, std::string>::const_iterator it;
};

inline std::ostream& operator<<(std::ostream& stream, const PhoneBook& pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}

#endif	/* PHONEBOOK_H */ 


But output is:


error: passing 'const const_iterator {aka const std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >}' as 'this' argument of 'std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >& std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >::operator=(const std::_Rb_tree_const_iterator<std::pair<const std::basic_string<char>, std::basic_string<char> > >&)' discards qualifiers [-fpermissive]
But it works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class PhoneBook {
public:
    void addAbonent(const Abonent& abonent);
    void delAbonent(const Abonent& abonent);
    friend std::ostream& operator<<(std::ostream& stream, PhoneBook a);
private:
    std::map<std::string, std::string> base;
    std::map<std::string, std::string>::iterator it;
};

inline std::ostream& operator<<(std::ostream& stream, PhoneBook pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}

#endif	/* PHONEBOOK_H */ 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include "PhoneBook.h"
#include "Abonent.h"
using namespace std;

int main(int argc, char** argv) {
    PhoneBook phoneBook;
    Abonent ivanov;
    Abonent petrov;
    Abonent sidorov;
    
    ivanov.setName("Ivanov Ivan");
    ivanov.setNumber("333-333");

    petrov.setName("Petrov Petr");
    petrov.setNumber("999-333");

    sidorov.setName("Sidorov Sird");
    sidorov.setNumber("111-123");
    
    phoneBook.addAbonent(ivanov);
    phoneBook.addAbonent(petrov);
    phoneBook.addAbonent(sidorov);

    cout << phoneBook << endl;
    
    phoneBook.delAbonent(petrov);

    cout << phoneBook << endl;

    return 0;
}


Output:

Ivanov Ivan: 333-333
Petrov Petr: 999-333
Sidorov Sird: 111-123

Ivanov Ivan: 333-333
Sidorov Sird: 111-123
I can see you having an iterator member to serve as a bookmark, but in your operator>> function, you should make a copy of the iterator in the function. Either that, or pass the object by non-const reference instead of value, so you can modify the bookmark of the original object.

Think about it:
The parameter is a reference to a constant object. This means the object cannot (and should not) be modified. In your previous version of the function, you break this rule by modifying the member variable
it
in the loop.
>> I can see you having an iterator member to serve as a bookmark
No, I don't need it. I don't use the iterator us a bookmark. It's my mistake. I must use: this->it = base.begin(); in this:

1
2
3
4
5
void PhoneBook::delAbonent(const Abonent& abonent) {
    this->it = base.begin();
    this->it = this->base.find(abonent.getName());
    this->base.erase(it);
}


// The parameter is a reference to a constant object. This means the object cannot (and should not) be modified. In your previous version of the function, you break this rule by modifying the member variable
it
in the loop.

Why the compile don't inform me about the error "the object cannot (and should not) be modified" in this example:
1
2
3
4
5
6
7
/*
void PhoneBook::delAbonent(const Abonent& abonent) {
    this->it = base.begin();
    this->it = this->base.find(abonent.getName());
    this->base.erase(it);
}
*/


I mean this line: this->base.erase(it);

I have two vision of my class:

Vision Number One. It works fine:

PhoneBook.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef PHONEBOOK_H
#define	PHONEBOOK_H

#include <map>
#include <string>
#include <utility>
#include <ostream>
#include "Abonent.h"

class PhoneBook {
public:
    void addAbonent(const Abonent& abonent);
    void delAbonent(const Abonent& abonent);
    friend std::ostream& operator<<(std::ostream& stream, PhoneBook a);
private:
    std::map<std::string, std::string> base;
    std::map<std::string, std::string>::iterator it;
};

inline std::ostream& operator<<(std::ostream& stream, PhoneBook pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}

#endif	/* PHONEBOOK_H */ 


PhoneBook.cpp
1
2
3
4
5
6
7
8
9
10
11
#include "PhoneBook.h"

void PhoneBook::addAbonent(const Abonent& abonent) {
    this->base[abonent.getName()] = abonent.getNumber();
}

void PhoneBook::delAbonent(const Abonent& abonent) {
    this->it = base.begin();
    this->it = this->base.find(abonent.getName());
    this->base.erase(it);
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include "PhoneBook.h"
#include "Abonent.h"
using namespace std;

int main(int argc, char** argv) {
    PhoneBook phoneBook;
    Abonent ivanov;
    Abonent petrov;
    Abonent sidorov;
    
    ivanov.setName("Ivanov Ivan");
    ivanov.setNumber("333-333");

    petrov.setName("Petrov Petr");
    petrov.setNumber("999-333");

    sidorov.setName("Sidorov Sird");
    sidorov.setNumber("111-123");
    
    phoneBook.addAbonent(ivanov);
    phoneBook.addAbonent(petrov);
    phoneBook.addAbonent(sidorov);

    cout << phoneBook << endl;
    
    phoneBook.delAbonent(petrov);

    cout << phoneBook << endl;

    return 0;
}


Output:

Ivanov Ivan: 333-333
Petrov Petr: 999-333
Sidorov Sird: 111-123

Ivanov Ivan: 333-333
Sidorov Sird: 111-123


Vision Number Two. It doesn't work:

I have this line:
 
friend std::ostream& operator<<(std::ostream& stream, const PhoneBook& a);


instead this:
 
friend std::ostream& operator<<(std::ostream& stream, PhoneBook a);


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef PHONEBOOK_H
#define	PHONEBOOK_H

#include <map>
#include <string>
#include <utility>
#include <ostream>
#include "Abonent.h"

class PhoneBook {
public:
    void addAbonent(const Abonent& abonent);
    void delAbonent(const Abonent& abonent);
    friend std::ostream& operator<<(std::ostream& stream, const PhoneBook& a);
private:
    std::map<std::string, std::string> base;
    std::map<std::string, std::string>::const_iterator it;
};

inline std::ostream& operator<<(std::ostream& stream, const PhoneBook& pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}

#endif	/* PHONEBOOK_H */ 


PhoneBook.cpp and main.cpp are same.


error: passing 'const const_iterator {aka const 
std::_Rb_tree_const_iterator<std::pair<const 
std::basic_string<char>, std::basic_string<char> > >}' as 
'this' argument of 
'std::_Rb_tree_const_iterator<std::pair<const 
std::basic_string<char>, std::basic_string<char> > >& 
std::_Rb_tree_const_iterator<std::pair<const 
std::basic_string<char>, std::basic_string<char> > 
>::operator=(const 
std::_Rb_tree_const_iterator<std::pair<const 
std::basic_string<char>, std::basic_string<char> > >&)' 
discards qualifiers [-fpermissive]


Thank you!
Last edited on
The important part of that error message is:
passing 'const const_iterator[']... discards qualifiers

Now let's look at the function:
1
2
3
4
5
6
inline std::ostream& operator<<(std::ostream& stream, const PhoneBook& pb) {
    for ((pb.it) = (pb.base.begin()); (pb.it) != (pb.base.end()); ++(pb.it)) {
        stream << pb.it->first << ": " << pb.it->second << std::endl;
    }
    return stream;
}


Your parameter is a constant object. Constants are constant; they cannot be modified, and any member of a constant object should also be constant (or read only for functions).
Now look at your for loop:
 
for((pb.it) = (pb.base.begin());/*...*/; ++(pb.it))

Here you modify a member of pb. But pb is constant, meaning pb.it, too, should be constant.
That's what the error means by "discards [const] qualifier".

Considering your operator>>() function, you should just create a new iterator instead of attempting to modify pb.it.
1
2
3
4
5
6
7
8
9
10
inline std::ostream& operator<<(std::ostream& stream, const PhoneBook& pb) {
    for (std::map<std::string, std::string>::const_iterator iter = (pb.base.begin()); iter != (pb.base.end()); ++iter) {
        stream << iter->first << ": " << iter->second << std::endl;
    }
//There is also the C++11 auto keyword redefinition, which would let you write
//for (auto iter = (pb.base.begin()); iter != (pb.base.end()); ++iter) {
//The type should be the same because begin() members return a
//   const_iterator when called with a const object
    return stream;
}
Last edited on
You solved my problem! Now I understand it. Thank you very much :)

//There is also the C++11 auto keyword redefinition, which would let you write
//for (auto iter = (pb.base.begin()); iter != (pb.base.end()); ++iter) {
//The type should be the same because begin() members return a
// const_iterator when called with a const object


I read about it in the book "Professional C++," 2 edition. I like this book. Thank you!
Last edited on
Topic archived. No new replies allowed.