Carles Araguz
Carles Araguz

Reputation: 1177

How to achieve const-correctness in multidimensional map in C++

I have a complex map that, in the end, stores pointers to Drawable objects. Drawable objects have a draw() member function which is declared as const. I need to call all the draw functions for all objects stored in my map that are of a certain type, and I must do it inside a const function. However I can't seem to be able to preserve the const-correctness of my function (drawSolid).

My outer map (map<int, ##>) is essentially indexing some sub-maps. Sub-maps are, in turn, indexing vectors (map<ItemType, vector<##> >). Finally, this vector keeps a set of shared_ptr<Drawable> objects.

If I remove the const qualifier from my function header, everything compiles, but I need it to be const. How may I iterate through my multidimensional map, preserving const-correctness?

void DrawableItems::drawSolid(int item_list = -1) const
{
    typedef std::map<int, std::map<ItemType, std::vector<std::shared_ptr<Drawable> > > > drawablemap;
    std::vector<std::shared_ptr<Drawable> > its;
    for(drawablemap::const_iterator li = __items.begin(); li != __items.end(); li++) {
        its = li->second[SOLID];
        for(auto di = its.begin(); di != its.end(); di++) {
            di->get()->draw();
        }
    }
}

This the error I get from the compiler (G++):

/.../dss-sim/src/graphics/DrawableItems.cpp: In member function ‘void DrawableItems::drawSolid(int) const’:
/.../dss-sim/src/graphics/DrawableItems.cpp:51:35: error: passing ‘const std::map<DrawableItems::ItemType, std::vector<std::shared_ptr<Drawable> > >’ as ‘this’ argument discards qualifiers [-fpermissive]
             its = li->second[SOLID];
                                   ^
In file included from /usr/include/c++/5/map:61:0,
                 from /.../dss-sim/src/common/dss.hpp:11,
                 from /.../dss-sim/src/graphics/DrawableItems.hpp:19,
                 from /.../dss-sim/src/graphics/DrawableItems.cpp:15:
/usr/include/c++/5/bits/stl_map.h:494:7: note:   in call to ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](std::map<_Key, _Tp, _Compare, _Alloc>::key_type&&) [with _Key = DrawableItems::ItemType; _Tp = std::vector<std::shared_ptr<Drawable> >; _Compare = std::less<DrawableItems::ItemType>; _Alloc = std::allocator<std::pair<const DrawableItems::ItemType, std::vector<std::shared_ptr<Drawable> > > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = std::vector<std::shared_ptr<Drawable> >; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = DrawableItems::ItemType]’
       operator[](key_type&& __k)

Upvotes: 2

Views: 167

Answers (1)

alain
alain

Reputation: 12047

There is no const version of operator[] in std::map. However, there is a const version of at() which you can use instead:

its = li->second.at(SOLID);

The reason is that operator[] inserts an element if there is no element yet, so there can not be a const version of operator[].
at() on the other hand throws an exception if no element exists, and this is compatible with a const std::map.

Upvotes: 2

Related Questions