2015-05-21 11 views
9

Piszę funkcję, która powinna otrzymać jedną z (std::map, std::multimap, std::unordered_map lub std::unordered_multimap). Mój kod jest następująca:Szablon funkcji odbierający dowolną standardową mapę

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; 
      } 
     } 

Szablon szablon parametr Map nie uogólniać na wszystkich typach map. Modele std::map i std::multimap odbierają cztery parametry szablonu, a std::unordered_map i std::unordered_multimap odbierają pięć parametrów szablonu. Oznacza to, że nie mogę rozwiązać problemu za pomocą parametru szablonu szablonu. Czy istnieje sposób rozwiązania tego problemu z ograniczeniem, że wszystkie mapy muszą mieć KeyType = ValeType = Coord? Nie chciałbym wyraźnie określać typów parametrów w wywołaniu filter.

Odpowiedz

1

Mimo że te klasy szablonów przyjmują różną liczbę argumentów, mają wartości domyślne, więc wszystkie mogą być tworzone z tylko dwoma. Jako taki, mógłby po prostu użyć zmiennej liczbie argumentów szablonu, a następnie coś, co nie jest instantiatable z dwoma argumentami spowoduje błąd kompilatora i tak:

template<template <class...> class Map, typename Coord> 
+0

To zakłada, że nie chcesz obsługiwać map z inną funkcją porządkowania lub inną wartością domyślną. Co wydaje się dziwne. – Yakk

4

Wystarczy napisać swój własny rodzaj cechę:

template <typename M, typename COORD> 
struct is_map_of_coord : std::false_type { }; 

które specjalizują się następnie do 5 map:

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. 

który pozwala przyjąć dowolną map, niezależnie od jego przydzielania, komparator, funkcji skrótu, etc, tak długo jak to Key/ValueCoord:

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 */ 
} 

Albo można skrócić, że tylko przy założeniu, że skoro wszystkie mapy mają key_type i mapped_type, upewnij się, że te obie istnieją i są takie same jak 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 
{ }; 
+0

Nie można wnioskować o podstawieniu słowa "Coord", należy wyraźnie określić. –

+0

@RaulAlonso Wystarczy dodać domyślny typ dla 'Coord', zaktualizowany. – Barry

4

Oznaczono tagiem C++ 11, więc spróbuję użyć parametrów szablonu variadic:

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; 
     } 
    } 

} 
Powiązane problemy