2015-05-21 7 views
9

Sto scrivendo una funzione che dovrebbe ricevere uno (std::map, std::multimap, std::unordered_map o std::unordered_multimap). Il mio codice è la seguente:Modello di funzione che riceve qualsiasi mappa standard

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

Il modello parametro di template Map non generalizzare per tutti i tipi di mappe. I modelli std::map e std::multimap ricevono quattro parametri modello e std::unordered_map e std::unordered_multimap ricevono cinque parametri modello. Ciò implica che non posso risolvere il problema con un parametro template template. C'è un modo per risolvere questo problema con il vincolo che tutte le mappe devono avere KeyType = ValeType = Coord? Non vorrei specificare esplicitamente i tipi di parametri in una chiamata a filter.

risposta

1

Anche se queste classi di modelli accettano un numero diverso di argomenti, hanno impostazioni predefinite, quindi possono essere tutte istanziate con solo due. Come tale, si potrebbe utilizzare un modello variadic, quindi tutto ciò che non è con istanze e due argomenti si tradurrà in un errore di compilazione in ogni caso:

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

Questo presuppone che tu non voglio supportare mappe con una funzione di ordinamento diversa, o un diverso hash dall'impostazione predefinita. Che sembra strano – Yakk

4

Basta scrivere il proprio tipo di tratto:

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

che poi specializzarsi per le 5 mappe:

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. 

che consente di accettare qualsiasi map, a prescindere dalla sua allocator, comparatore, funzione di hash, ecc, fino a quando si tratta di Key/Value sono 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 */ 
} 

Oppure si può abbreviare tale da solo assumendo che dal momento che tutte le mappe hanno una key_type e mapped_type, verificare che chi sia esistono e sono gli stessi 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

Non può inferire la sostituzione per 'Coord', deve specificare esplicitamente. –

+0

@RaulAlonso Basta aggiungere un tipo predefinito per 'Coord', aggiornato. – Barry

4

Hai taggato C++ 11 quindi proverei a utilizzare i parametri del modello 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; 
     } 
    } 

} 
Problemi correlati