2013-05-10 10 views
12

Ho un problema in cui ho bisogno di mappare un numero intero in fase di compilazione a un altro numero intero. Fondamentalmente, ho bisogno dell'equivalente in fase di compilazione di std::map<int,int>. Se non trovi una chiave nella mappa, mi piacerebbe restituire un valore predefinito.Come creare una chiave/un archivio di valori in fase di compilazione?

L'interfaccia che vorrei utilizzare:

template<unsigned int default_value, 
     unsigned int key0, unsigned int value0, 
     unsigned int key1, unsigned int value1, 
     ...> 
struct static_map 
{ 
    ... 
}; 

template<unsigned int key, typename StaticMap> 
struct lookup 
{ 
    static unsigned int value = ... 
}; 

lookup restituisce il valore associato key nel StaticMap. Se key non viene trovato, viene restituito default_value.

In generale, il numero di coppie chiave/valore sarà limitato da qualche limite> 2. Qual è il modo migliore per creare static_map e lookup?

Vorrei anche menzionare che sono limitato all'utilizzo di costrutti di linguaggio C++ 03, quindi non C++ 11 e nessuna dipendenza di librerie esterne.


Ecco la soluzione alla quale sono arrivato, ispirata da n. e le risposte di dyp di seguito:

#include <iostream> 

template<unsigned int k, unsigned int v> 
struct key_value 
{ 
    static const unsigned int key = k; 
    static const unsigned int value = v; 
}; 


template<typename Head, typename Tail = void> 
struct cons 
{ 
    template<unsigned int key, unsigned int default_value> 
    struct get 
    { 
    static const unsigned int value = (key == Head::key) ? (Head::value) : Tail::template get<key,default_value>::value; 
    }; 
}; 


template<typename Head> 
struct cons<Head,void> 
{ 
    template<unsigned int key, unsigned int default_value> 
    struct get 
    { 
    static const unsigned int value = (key == Head::key) ? (Head::value) : default_value; 
    }; 
}; 


template<unsigned int default_value, 
     unsigned int key0, unsigned int value0, 
     unsigned int key1, unsigned int value1, 
     unsigned int key2, unsigned int value2, 
     unsigned int key3, unsigned int value3, 
     unsigned int key4, unsigned int value4, 
     unsigned int key5, unsigned int value5, 
     unsigned int key6, unsigned int value6, 
     unsigned int key7, unsigned int value7> 
struct static_map 
{ 
    template<unsigned int key> 
    struct get 
    { 
    typedef cons< 
     key_value<key0,value0>, 
     cons< 
     key_value<key1,value1>, 
     cons< 
      key_value<key2,value2>, 
      cons< 
      key_value<key3,value3>, 
      cons< 
       key_value<key4,value4>, 
       cons< 
       key_value<key5,value5>, 
       cons< 
        key_value<key6,value6>, 
        cons< 
        key_value<key7,value7> 
        > 
       > 
       > 
      > 
      > 
     > 
     > 
    > impl; 

    static const unsigned int value = impl::template get<key,default_value>::value; 
    }; 
}; 


template<unsigned int key, typename StaticMap> 
struct lookup 
{ 
    static const unsigned int value = StaticMap::template get<key>::value; 
}; 


int main() 
{ 
    typedef static_map<13, 
        0, 0, 
        1, 10, 
        2, 20, 
        3, 30, 
        4, 40, 
        5, 50, 
        6, 60, 
        7, 70 
    > my_static_map; 

    std::cout << "0 maps to " << lookup<0, my_static_map>::value << std::endl; 
    std::cout << "1 maps to " << lookup<1, my_static_map>::value << std::endl; 
    std::cout << "2 maps to " << lookup<2, my_static_map>::value << std::endl; 
    std::cout << "3 maps to " << lookup<3, my_static_map>::value << std::endl; 
    std::cout << "4 maps to " << lookup<4, my_static_map>::value << std::endl; 
    std::cout << "5 maps to " << lookup<5, my_static_map>::value << std::endl; 
    std::cout << "6 maps to " << lookup<6, my_static_map>::value << std::endl; 
    std::cout << "7 maps to " << lookup<7, my_static_map>::value << std::endl; 
    std::cout << "100 maps to " << lookup<100, my_static_map>::value << std::endl; 

    return 0; 
} 
+0

possibile duplicato di [inizializzazione di uno std :: statica mappa in C++] (http://stackoverflow.com/questions/138600/initializing-a-static-stdmapint-int-in-c) – user93353

+5

@ user93353: questa domanda non è correlata alla domanda che hai collegato. –

+0

@DyP: Sì, qualcosa come la mappa MPL di boost è ciò di cui ho bisogno. Sfortunatamente, non posso dipendere da MPL, quindi mi piacerebbe capire l'implementazione. –

risposta

11

In C++ 11:

template <int kk, int vv> 
struct kv 
{ 
    static const int k = kk, v = vv; 
}; 

template <int dflt, typename...> 
struct ct_map; 

template <int dflt> 
struct ct_map<dflt> 
{ 
    template<int> 
    struct get 
    { 
     static const int val = dflt; 
    }; 
}; 

template<int dflt, int k, int v, typename... rest> 
struct ct_map<dflt, kv<k, v>, rest...> 
{ 
    template<int kk> 
    struct get 
    { 
     static const int val = 
      (kk == k) ? 
      v : 
      ct_map<dflt, rest...>::template get<kk>::val; 
    }; 
}; 

typedef ct_map<42, kv<10, 20>, kv<11, 21>, kv<23, 7>> mymap; 

#include <iostream> 
int main() 
{ 
    std::cout << mymap::get<10>::val << std::endl; 
    std::cout << mymap::get<11>::val << std::endl; 
    std::cout << mymap::get<23>::val << std::endl; 
    std::cout << mymap::get<33>::val << std::endl; 
} 
+0

Non è richiesta una definizione di 'kv :: k' e' kv :: v' (al di fuori della classe)? – dyp

+0

@DyP: no, perché non sono usati odr. –

+0

Come si genera un errore in fase di compilazione se non si trova una chiave? – karliwson

3

Qualcosa di simile a questo dovrebbe funzionare:

template<int Key> 
struct StaticMap { 
    static const int Value = 0; 
}; 

template<> 
struct StaticMap<1> { 
    static const int Value = 3; 
}; 

int main() 
{ 
    cout << StaticMap<0>::Value << ", " 
     << StaticMap<1>::Value << ", " 
     << StaticMap<2>::Value << endl; 
} 

0 è il valore di default, e una chiave di 1 dà un valore di 3. Aggiungi specializzazioni aggiuntivi, se necessario.

È questa l'idea generale di ciò che stai cercando? Non è l'interfaccia richiesta, sebbene le macro del preprocessore (come Boost.Preprocessor) possano semplificare e semplificare l'impostazione.

1

È possibile utilizzare modello di specializzazione

template <char key> 
struct Map; 

template <char key> 
struct Map { static const int value = -1; }; // not exists node 

template <> struct Map< 'A' > { static const int value = 1; }; // 'A' -> 1 
template <> struct Map< 'B' > { static const int value = 2; }; // 'B' -> 2 
// .... 

int lookup = Map<'B'>::value; // = 2 

È possibile avvalersi di alcune macro per semplificare la definizione dei contenuti.

2

Essenzialmente basato sull'ereditarietà: ogni istanza di mappa eredita i tipi di ricerca delle sue classi di base (-> riduci il problema) e definisce una ricerca per una chiave.

Modifica: versione migliorata in base alle idee della n.

#include <iostream> 
#include <cstddef> 

template < int t_key, int t_value > 
struct ct_int_pair 
{ 
    enum { key = t_key, value = t_value }; 
}; 

struct dummy; 

template < int default_value, 
      typename key_value_pair0, 
      typename key_value_pair1 = dummy, 
      typename key_value_pair2 = dummy > 
struct ct_map 
    : ct_map < default_value, key_value_pair1, key_value_pair2, dummy > 
{ 
    typedef ct_map < default_value, key_value_pair1, key_value_pair2, dummy > base; 

    // DUMMY required for partial specialization 
    template < int key, class DUMMY = dummy > 
    struct lookup 
    { 
     enum { value = base::template lookup <key> :: value }; 
    }; 
     template < class DUMMY > 
     struct lookup < key_value_pair0::key, DUMMY > 
     { 
      enum { value = key_value_pair0::value }; 
     }; 
}; 

    template < int default_value > 
    struct ct_map < default_value, dummy, dummy, dummy > 
    { 
     template < int key > 
     struct lookup 
     { 
      enum { value = default_value }; 
     }; 
    }; 


template < int key, typename StaticMap > 
struct lookup 
{ 
    enum { value = StaticMap :: template lookup <key> :: value }; 
}; 


// example 

typedef ct_map < -1, 
       ct_int_pair<21, 42>, 
       ct_int_pair<10, 15> > my_map; 

enum 
{ 
    value0 = lookup<21, my_map>::value 
    , value1 = lookup<10, my_map>::value 
    , value2 = lookup<100, my_map>::value 
}; 

int main() 
{ 
    std::cout << value0 << " : " << value1 << " : " << value2 << std::endl; 
} 
Problemi correlati