0

I am implementing a class using a map, like so:

class Letras {
    typedef std::pair<int, int> p_c;
    std::map<char, p_c> bolsa;
public:
    ...
};

And I'd like to implement the functionality of an iterator, to be used like so:

Letras l;

Letras::iterator it;
for ( it = l.begin(); it != l.end(); ++it )
    cout << *it << endl;

So that it prints out the chars from the std::map first component (key).

Thanks in advance.

More information about Letras

Letras is a class that implements a Scrubble-like letter set, the map is used to represent a set of letras (letters in Spanish) like the following:

{{letter_1, {quantity_1, score_1}}, {letter_2, {quantity_2, score_2}}, ..., {letter_n, {quantity_n, score_n}}}

Where letter_i is a certain letter from the set, quantity_i is the amount of times that letter is in the set (a Scrubble-like letter set can have various identical letters) and score_i is the letter score.

I have used a map because a letter can only have an associated score, so that in this class, i != j => letter_i != letter_j.

The utility of Letras is to find the best words formed by a certain letter set from a Diccionario class (dictionary), another class that has implemented a DAWG structure for fast search and lookup.

mianfg
  • 15
  • 8
  • 2
    You haven't asked a question. – Kerrek SB Jan 04 '19 at 01:27
  • @KerrekSB I'm asking for hints at implementing this, I have been able to correctly implement iterator for other classes, but not for classes that use the STL – mianfg Jan 04 '19 at 01:30
  • Looks like a kind of "transform iterator" is called for here. (Boost has such a thing.) – Kerrek SB Jan 04 '19 at 01:35
  • 1
    @mianfg What do you want to return when `*l` is called? Shouldn't it be `*it`? – Kunal Puri Jan 04 '19 at 01:36
  • @KunalPuri I am incredibly sorry for the typo, it's of course `*it` instead of `*l` – mianfg Jan 04 '19 at 01:38
  • Some very good advice on this topic to be [found in this Q&A](https://stackoverflow.com/questions/7758580/writing-your-own-stl-container). – user4581301 Jan 04 '19 at 01:39
  • @user4581301 Thanks so much! However, my main problem is at implementation. I have a rough idea on how to declare the class in the header, however I do not know how to correctly reference my class object (especially in `begin()`/`end()` and `operator++()` (and the `--`, `==`, `!=` overloads) – mianfg Jan 04 '19 at 01:44
  • For that we need to know a lot more about `Letras` and its purpose. – user4581301 Jan 04 '19 at 01:49
  • @user4581301 I have updated the question with more information – mianfg Jan 04 '19 at 01:57
  • @mianfg Why do you need to access only first value of a pair using iterator? – Kunal Puri Jan 04 '19 at 01:59

1 Answers1

2

You can do something like this:

#include <iostream>
#include <map>
#include <algorithm>

using namespace std;

class Letras {
private:
    typedef std::pair<int, int> p_c;
    std::map<char, p_c> bolsa;

public:
    class iterator {
    private:
        std::map<char, p_c>::iterator it;

    public:
        iterator(const std::map<char, p_c>::iterator &it) {
            this->it = it;
        }

        // EDIT: Removing Copy Semantics
        iterator(const iterator &it) = delete;
        iterator &operator =(const iterator &it) = delete;

        // EDIT: Enabling Move Semantics
        iterator(iterator &&it) = default;
        iterator &operator =(iterator &&it) = default;

        auto &operator *() const {
            return it->first;
        }

        iterator &operator ++(int) {
            this->it++;
            return *this;
        }

        bool operator !=(const iterator &it) {
            return this->it != it.it;
        }
    };

    auto begin() {
        return iterator(bolsa.begin());
    }

    auto end() {
        return iterator(bolsa.end());
    }

    void insert(const std::pair<char, p_c> &p) {
        bolsa.insert(p);
    }
};

int main() {
    Letras b;
    b.insert(make_pair('f', make_pair(1, 2)));
    b.insert(make_pair('g', make_pair(1, 2)));
    b.insert(make_pair('h', make_pair(1, 2)));

    for (auto it = b.begin(); it != b.end(); it++) {
        cout << *it << endl;
    }

    return 0;
}
Kunal Puri
  • 3,419
  • 1
  • 10
  • 22
  • Thanks so much! However, I also needed to implement the default constructor to be able to declare `Letras::iterator it` -- I implemented it setting it to NULL: `iterator() : it(0) {}` and it works fine! – mianfg Jan 04 '19 at 02:04
  • One question, why do you declare `operator++` as `iterator& operator++(int)`? What does that `int` do? – mianfg Jan 04 '19 at 02:07
  • @mianfg I think `iterator() : it(0) {}` is not a recommended practice. See https://stackoverflow.com/questions/27817732/stdmap-iterator-initialization-by-zero-in-c – Kunal Puri Jan 04 '19 at 02:08
  • @mianfg For operator ++ info, see this: https://stackoverflow.com/questions/7740350/overloading-postfix-and-prefix-operators – Kunal Puri Jan 04 '19 at 02:09
  • @mianfg Why do you need default constructor by the way? – Kunal Puri Jan 04 '19 at 02:13
  • it didn't compile if I didn't implement it. On other means, what's the *removing copy semantics* and *enabling move semantics* part about? – mianfg Jan 04 '19 at 19:46
  • @mianfg It should have compiled without writing default constructor. You might be misusing the `iterator` somewhere. – Kunal Puri Jan 04 '19 at 23:57
  • @mianfg Regarding copy and move semantics, you may google them. Essentially, I removed copy semantics to stop the user from making copes of `iterator` – Kunal Puri Jan 04 '19 at 23:58