1

I'm trying to make a wrapper to the STL map container, in order to add a const method to return the value given the key. In map, operator[] isn't const, and find() requires dereferencing to get the value (map.find()->second). I'm basing some of my "research" off of Idiomatic C++ for reading from a const map by the way.

The code so far (all inside a single header file):

#include <map>
template <typename K, typename V>
class easymap : public std::map<K, V>
{
    //Constructor
    easymap() : std::map<K, V>() {};

    //The get method
    V get(K key)
    {
        std::map<K, V>::const_iterator iter(find(key));
        return iter != end() ? iter->second : V();
    }
};

When I try to compile this, I get the following errors:

In member function `V easymap::get(K)':
    expected `;' before "iter"
`iter' was not declared in this scope
there are no arguments to `end' that depend on a template parameter, so a declaration of `end' must be available|
(if you use `-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)

Does how I'm trying to go about doing this make sense? If so, how do I make this work? If not, how would I go about achieving the effect I'm looking for?

Community
  • 1
  • 1
Lewis
  • 1,310
  • 1
  • 15
  • 28
  • Also have a look at [this](http://stackoverflow.com/questions/2396019/c-templates-hides-parent-members) thread. – Prasoon Saurav Oct 17 '10 at 08:25
  • Note that the accepted answer in that thread just implements this as a free function. There isn't really that much difference between `map.get(x);` and `get(map, x);` - You are also forgetting that a map has two more template parameters (predicate and allocator). – UncleBens Oct 17 '10 at 09:22

3 Answers3

3

Do not derive from std::map. Rather, wrap a std::map instance in your easymap, following the composition before inheritance principle. Besides of all the technical reasons, this reflects the design intent much better: provide a simplified API to map hiding the default one:

template<typename K, typename V>
class easymap {
 std::map<K, V> mMap;
public:
  V Get(K Key) const {
   // ...
  }
};
Paul Michalik
  • 4,331
  • 16
  • 18
2

You are missing the template parameters for map, you have to specify typename when declaring the iterator (see here), and for some reason unknown to me (probably a namespace conflict) you have to use this when calling end():

template <typename K, typename V>
class easymap : public std::map<K,V>
{
    //Constructor
    easymap() : std::map<K, V>() {};

    //The get method
    V get(K key)
    {
        typename std::map<K, V>::const_iterator iter(find(key));
        return iter != this->end() ? iter->second : V();
    }
};
Community
  • 1
  • 1
Alejandro
  • 3,726
  • 1
  • 23
  • 29
  • 3
    Regarding the `this`, there are some other ways also. See FAQ item [35.19 Why am I getting errors when my template-derived-class uses a member it inherits from its template-base-class?](http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19). Cheers & hth., – Cheers and hth. - Alf Oct 17 '10 at 07:47
  • Thanks so much, that worked perfectly! Good information on typename, something I definitely should have read up on by now, as well as the tip to use this->end(), which I agree, makes little sense. G++'s error message on that doesn't help a whole lot either (to me at least) – Lewis Oct 17 '10 at 07:48
2

It's no a good idea to use STL container as base class. You should have a really good reason to do that and to be very careful.

The reason is, that none of the STL containers have a virtual destructor. So, if you have a pointer, for example std::map<..> *, that points to your object (that has inherited the map), one of the destructors will not be called. This is a 100% memory leak.

Related question to this one is: Is it okay to inherit implementation from STL containers, rather than delegate?

Community
  • 1
  • 1
Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187