I am writing a function that should receive one of (std::map
, std::multimap
, std::unordered_map
or std::unordered_multimap
). My code is as follow:
template<template <class, class> class Map, typename Coord>
inline typename std::enable_if<std::is_arithmetic<Coord>::value>::type
filter(Map<Coord, Coord>& map, Coord step = 2) {
for (auto it = std::begin(map); it != std::end(map);) {
if (it->second - it->first <= step){
it = map.erase(it);
}
else
++it;
}
}
The template template parameter Map
does not generalize for all types of maps. The std::map
and std::multimap
receive four template parameters, and std::unordered_map
and std::unordered_multimap
receive five template parameters. This implies that I can not solve the problem with a template template parameter. Is there any way to solve this with the constraint that all maps must have KeyType = ValeType = Coord
? I would not like to specify explicitly the parameters types in a call to filter
.
You tagged c++11 so I would try to use variadic template parameters:
template<template <class ... > class Map, typename Coord, typename ... MapParms >
inline typename std::enable_if<std::is_arithmetic<Coord>::value>::type
filter(Map<Coord, Coord, MapParms... >& map, Coord step = 2)
{
for (auto it = std::begin(map); it != std::end(map);)
{
if (it->second - it->first <= step)
{
it = diagram.erase(it);
}
else
{
++it;
}
}
}
Just write your own type trait:
template <typename M, typename COORD>
struct is_map_of_coord : std::false_type { };
That you then specialize for the 5 maps:
template <typename COORD, typename C, typename A>
struct is_map_of_coord<std::map<COORD, COORD, C, A>, COORD>
: std::true_type { };
template <typename COORD, typename H, typename K, typename A>
struct is_map_of_coord<std::unordered_map<COORD, COORD, H, K, A>, COORD>
: std::true_type { };
etc.
Which lets you accept any map
, regardless of its allocator, comparator, hash function, etc, as long as it's Key
/Value
are Coord
:
template <typename Map, typename Coord = int>
inline typename std::enable_if<
std::is_arithmetic<Coord>::value &&
is_map_of_coord<Map, Coord>::value
>::type
filter(Map& map, Coord step = 2) {
/* body */
}
Or you can shorten that by just assuming that since all the maps have a key_type
and mapped_type
, verify that those both exist and are the same as COORD
:
template <typename...>
using void_t = void;
template <typename M, typename COORD, typename = void>
struct is_map_of_coord : std::false_type { };
template <typename M, typename COORD>
struct is_map_of<M, K, void_t<
std::enable_if_t<std::is_same<typename M::key_type, COORD>::value>,
std::enable_if_t<std::is_same<typename M::mapped_type, COORD>::value>
> >
: std::true_type
{ };
Although those template classes take a different number of arguments, they have defaults, so can all be instantiated with just two. As such, you could just use a variadic template, then anything which isn't instantiatable with two arguments will result in a compiler error anyway:
template<template <class...> class Map, typename Coord>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With