2013-05-10 6 views
12

コンパイル時に整数を別の整数にマップする必要があるという問題があります。基本的には、コンパイル時にはstd::map<int,int>相当のものが必要です。マップにキーが見つからない場合は、デフォルト値を返したいと思います。コンパイル時のキー/値ストアを構築するには?

インタフェース私が使用したい:

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

StaticMapkeyに関連付けられている値を返しますlookupkeyが見つからない場合は、default_valueが返されます。

一般的に、キーと値のペアの数は、いくつかの制限> 2で制限されます。static_maplookupをビルドする最良の方法は何ですか?

また、私はC++ 03の言語構成を使用することに限定しているので、C++ 11と外部ライブラリの依存関係は使用できません。


これは、nMに触発された解決方法です。以下DYPの答え:

#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

の可能重複[静的STDを初期化::マップ C++で(http://stackoverflow.com/questions/138600/initializing-a-static-stdmapint-int-in-c) – user93353

+5

@ user93353:この質問はあなたがリンクした質問とは無関係です。 –

+0

@DyP:はい、boostのMPLマップのようなものが必要です。残念ながら、私はMPLに依存することができないので、実装を理解したいと思います。 –

答えて

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

'kv :: k'と' kv :: v'の定義がクラス外では必要ないのですか? – dyp

+0

@DyP:いいえ、odrが使用されていないためです。 –

+0

キーが見つからない場合、どのようにコンパイル時エラーがスローされますか? – karliwson

3

はこのような何かが働くだろう:

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はデフォルト値であり、1のキーは、必要に応じて3の値は、追加の専門分野を追加できます。

これはあなたが探している一般的な考えですか?プリプロセッサマクロ(Boost.Preprocessorなど)は設定を合理化し簡単にすることができますが、リクエストしたインターフェイスではありません。 C++ 11では

1

あなたは、コンテンツの定義を簡素化するためにいくつかのマクロを堪能することができますテンプレートの特殊

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 

を使用することができます。

2

基本的に継承に基づいています:すべてのマップインスタンス化は、基本クラスのルックアップタイプを継承します( - > reduce問題)。キーのルックアップを定義します。

編集:n.m.のアイデアを改善したバージョンベース。

#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; 
} 
関連する問題