Kris
Kris

Reputation: 65

Specialize hashmap template

I'm using the hash_map in C++ and want to supply a simplified type name for it:

The key type and hasher function are always the same.

stdext::hash_map<std::string, [MAPPED TYPE], CStringHasher>

However, I don't really want to write all this every time I declare a hash map which maps strings to type X.

So the above declaration would look like:

template<typename T> StringHashmap = stdext::hash_map<std::string, T, CStringHasher>

StringHashmap<int> mapA; //Maps std::string to int
StringHashamp<bool> mapB; //Maps std::string to bool

Upvotes: 3

Views: 1115

Answers (3)

Luc Touraille
Luc Touraille

Reputation: 82041

As others said, template aliases is the way to go if you can use C++0x:

template < typename MappedType >
using StringHashMap = stdext::hash_map< std::string, MappedType, CStringHasher >;

StringHashMap< int > mapA;
StringHashMap< bool > mapB;

(As @MSalters noted, if you have C++0x available, you should probably use std::unordered_map.)

Otherwise, you can still use the usual workaround, which is to define a class template containing a typedef:

template < typename MappedType >
struct StringHashMap
{
    typedef stdext::hash_map< std::string, MappedType, CStringHasher > type;
};

StringHashMap< int >::type mapA;
StringHashMap< bool >::type mapB;

A drawback with this solution (which have engendered many questions here on SO) is that you sometimes need to prefix StringHashMap< T >::type by the typename keyword in order to assert to the compiler that this name effectively denotes a type. I will not dwell on this subject in this answer, you can check out this FAQ, and especially the accepted answer, for more information. (Thanks to @sbi for evoking this matter.)

Upvotes: 5

templatetypedef
templatetypedef

Reputation: 372724

With the current version of C++ (C++03), there really isn't a good way to do this. You could try something like

#define StringHashMap(type) stdext::hash_map<std::string, type, CStringHasher>

But then you run into trouble if you try to specify a template type with a comma in it, like this:

StringHashMap(pair<int, string>) myMap; // Error!

This fails because the preprocessor will tokenize this as

StringHashMap((pair<int), (string>)) myMap; // Error!

which isn't what you want. If you're not going to do anything like this, though, you should be fine. You could alternatively use typedefs to get around it:

typedef pair<int, int> IntPair;
StringHashMap(IntPair) myMap; // Okay

If you're allowing use of C++0x features, you can use a template using declaration, like this one here:

template <typename T>
    using StringHashMap = stdext::hash_map<std::string, T, CStringHasher>;

Unfortunately, C++03 doesn't have a "template typedef" feature like this one, so you'd have to use a newer compiler and won't have as good a portability guarantee.

Hey, wait a minute! My name is templatetypedef and this is the first time on Stack Overflow that I've ever written that phrase in an answer! You just made my night. :-)

Upvotes: 2

Scott Langham
Scott Langham

Reputation: 60351

If you're using C++ 0x, template typedefs were designed to do exactly this kind of thing:

http://en.wikipedia.org/wiki/C%2B%2B0x#Template_aliases

Upvotes: 1

Related Questions