CHardnett
CHardnett

Reputation: 164

Dropping "const int" qualifiers in template operator[]

I have looked at several post about const qualifiers, but I am not able to figure out how to fix this issue. I am building a class that is modeled after the STL map class, and I am using the STL set class as the base class:

template <class Key, class Value>
class map : public std::set <std::pair<Key, Value> > {
public:
    typedef std::set<std::pair<Key, Value> > parent;
    typedef typename std::set<std::pair<Key, Value> >::iterator iterator;

    // constructors
    map() : parent() {}
    map(map<Key, Value>& m) : parent(m) {}

    // definition for subscript operator
    Value& operator [] (const Key &);

    // overloaded methods from set
    void erase(Key&);
    void erase(iterator& itr) {
        parent::erase(itr);
    }

    int count(Key&);
    iterator find(Key&);
    iterator lower_bound(Key& k) {
        return parent::lower_bound(k);
    }

    iterator upper_bound(Key& k) {
        return parent::upper_bound(k);
    }

    // not found iterator
    iterator end() {
        return parent::end();
    }

};

The problem is with the operator[] overload function, which looks like:

template <class Key, class Value>
Value&  map<Key, Value>::operator[] (const Key& k) {
    std::pair<Key, Value> test;
    test.first = k;

    std::pair<iterator, bool> where = parent::insert(test);

    return (*(where.first)).second;
}

The compiler is giving me the error "...map.h:108:16: Binding of reference to type 'int' to a value of type 'const int' drops qualifiers". I realize that it's seeing that (*(where.first)).second is evaluated to a "const int" and I am returning it to an "int" because I have declared a map as:

map<std::string, int> mymap;
mymap["one"] = 1;

It appears that the std::pair<...> is being defined as std::pair<std::string, const int> instead of std::pair<std::string, int>. At least this is my conjecture. I must be missing something simple, but I am not seeing it. Any help is greatly appreciated.

Upvotes: 1

Views: 1918

Answers (1)

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272687

The issue is that std::set elements are immutable (otherwise you could arbitrarily modify them and mess up the ordering without the set knowing about it); this is enforced by its method returning const iterators.

Therefore, *(where.first) is const, and therefore so is (*(where.first)).second. So you can't return a non-const reference to it.

Upvotes: 3

Related Questions