hookenz
hookenz

Reputation: 38889

"class std::map used without template paramaters" error

I'd have to say I'm no expert on using the STL. Here's my problem, I have a class Called LdapClientManager which maintains a number of LDAP clients that are managed by ID. The container holding the LdapClients is declared as a member variable i.e.

typedef std::map<int, LdapClient *> LdapClientMap;
LdapClientMap _ldapClientMap;

The following function fails to compile with the error:

LdapClient * LdapClientManager::getLdapClient(unsigned int templateID)
{
    // Do we have an LdapClient
    LdapClientMap::const_iterator it = _ldapClientMap.find(templateID);
    if (it == std::map::end) {
        // no existing client, lets create it
        LdapClient * ldapClient = new LdapClient();
        if (ldapClient == NULL) {
            // TODO: handle out of memory condition
        }

        _ldapClientMap[templateID] = ldapClient;
        return ldapClient;
    }

    return it->second;
}

Unfortunately I get the following error at compile time, what does it mean. I haven't found a solution in google as yet.

LdapClientManager.cc: In member function LdapClient* LdapClientManager::getLdapClient(unsigned int)': LdapClientManager.cc:33:template class std::map' used without template parameters

Upvotes: 2

Views: 6707

Answers (4)

navigator
navigator

Reputation: 1596

LdapClientMap _ldapClientMap;

You should avoid using names with a leading underscore. Technically it is undefined behavior, even if the compiler allows it because by using it you conflict with current or future reserved names.

Upvotes: -1

Timo Geusch
Timo Geusch

Reputation: 24341

std::map::end() is a member function of the container instance and not a universal value, so you'll need to check the result of std::map::find() against _ldapClientMap.end().

Another couple of suggestions to improve the code:

  • Standard C++ containers have value semantics (they want to store the actual object and not a pointer to the object). If you really need to store pointers to LdapClients instead of the LdapClient objects themselves, I would strongly recommend wrapping them in an appropriate smart pointer like boost::shared_ptr (not std::auto_ptr, which will not work). This way, the automatic memory management of the std::map will still work and destroy the objects as intended. If you don't want to use a smart pointer or put the actual LdapClient object into the container, you will have to manually manage the objects' lifetime and call delete when appropriate to prevent memory leaks. My preference would be to change the type of the map to std::map unless the LdapClient objects are polymorphic.
  • Unless you are using a very out of date compiler, checking the result of regular new() against 0 or NULL will not yield any new insights as new throws a std::bad_alloc these days when it can't allocated memory for whatever reason.
  • Instead of using _ldapClientMap[x] = y; to insert a new element, I would use _ldapClientMap.insert(LdapClientMap::value_type(x,y)) as the latter will not overwrite an existing value for key x (which the former will do) and will return 'false' in case the key already exists in the map. That is of course if that is your intention.

Upvotes: 1

avakar
avakar

Reputation: 32635

Replace std::map::end with _ldapClientMap.end(). Also, new never returns 0, it throws an exception if the allocation fails.

Note that the program can be made much shorter.

LdapClient * LdapClientManager::getLdapClient(unsigned int templateID)
{
    LdapClient *& value = _ldapClientMap[templateID];
    if (value == 0)
        value = new LdapClient();
    return value;
}

Upvotes: 11

Rob Kennedy
Rob Kennedy

Reputation: 163257

It means exactly what it says it means. std::map is a class template. It is not a class in and of itself. It needs template parameters, like you used when you defined the LdapClientMap type. Later, you say std::map::end, and the compiler says that needs parameters, too.

But you probably meant _ldapClientMap.end(). Each map has its own end; end is not a static function, so you need to call it on an instance. If it were static, you would have needed to provide template parameters, just like when you defined the type: std::map<int, LdapClient*>::end.

Upvotes: 3

Related Questions