简体   繁体   中英

Template class that takes a template class as template won't compile

I'm trying to make a class that takes a map as a template parameter. In particular it should be able to take std::map and boost::ptr_map. Currently I'm trying this:

template <template<typename, typename> class MAP, typename KEYTYPE, typename DATATYPE>
class RestrictedMapBase
{
   /* bunch of methods ... */
}

This class is being inherited by two other classes, one for std::map and one for boost::ptr_map.

template <typename KEYTYPE, typename DATATYPE>
class RestrictedMap: public RestrictedMapBase<std::map, KEYTYPE, DATATYPE>
{
   /* Bunch of methods ... */
};

template <typename KEYTYPE, typename DATATYPE>
class RestrictedPointerMap: public RestrictedMapBase<boost::ptr_map, KEYTYPE, DATATYPE>
{
   /* Bunch of methods ... */
};

But on compilation I get these errors:

RestrictedMap.h(166) : error C3201: the template parameter list for class template 'std::map' does not match the template parameter list for template parameter 'MAP' RestrictedMap.h(183) : see reference to class template instantiation 'STLUtils::RestrictedMap' being compiled

RestrictedMap.h(186) : error C3201: the template parameter list for class template 'boost::ptr_map' does not match the template parameter list for template parameter 'MAP' RestrictedMap.h(203) : see reference to class template instantiation 'STLUtils::RestrictedPointerMap' being compiled

Can anybody point me in the right direction of what I'm doing wrong? Thanks.

std::map expects a template parameter to define what it is a map of. See below:

template <typename KEYTYPE, typename DATATYPE>
class RestrictedMap: public RestrictedMapBase<std::map<KEYTYPE, DATATYPE>, KEYTYPE, DATATYPE>
{
   /* Bunch of methods ... */
};

Your base class template parameters KEYTYPE and DATATYPE then become redundant. You can replace those with the typedefs provided in std::map's class:

std::map<_Kty, _Ty>::key_type; // This is the same as KEYTYPE
std::map<_Kty, _Ty>::mapped_type; // This is the same as DATATYPE

I would re-write your class something like this (I haven't tested this):

template <typename Map>
class RestrictedMap
{
public: // Typedefs
    typedef typename Map::key_type KeyType;
    typedef typename Map::mapped_type MapType;

public: // Methods
    // TODO: Write your methods here.
    void Add(const KeyType &key, const MapType &map);

private: // Members
    Map m_map;
};

Then you could choose your map like this (again un-tested):

typedef RestrictedMap<std::map<int, int>> StlMap; // TODO: Change your map's key and data type
typedef RestrictedMap<boost::ptr_map<int, int>> BoostMap; // TODO: Change your map's key and data type

Full example available here - http://ideone.com/U3AkV

Class template std::map have 4 arguments:

template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
          typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
class map

Thus it can not be pass via template<typename, typename> just like you can not assign a pointer to a 3-argument function to a pointer to 2-argument function.

The solution is to pass the exact type to use to RestrictedMapBase :

template <typename MAP>
class RestrictedMapBase
{
   typedef typename MAP::key_type KEYTYPE;
   typedef typename MAP::mapped_type DATATYPE;
};

Your initial design also limits users of your class because they can not specify a compare function for keys (or a hash function if they want to use hash tables) and an allocator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM