Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
140 views
in Technique[技术] by (71.8m points)

c++ - How to build a compile-time key/value store?

I have a problem where I need to map an integer at compile time to another integer. Basically, I need the compile-time equivalent of std::map<int,int>. If a key is not found in the map, I'd like to return a default value.

The interface I'd like to use:

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 returns the value associated with key in the StaticMap. If key is not found, then default_value is returned.

In general, the number of key/value pairs will be bounded by some limit > 2. What is the best way to build static_map and lookup?

I should also mention that I'm limited to using C++03 language constructs, so no C++11, and no external library dependencies.


Here's the solution I arrived at, inspired by n.m. and DyP's answers below:

#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;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...