如何构建编译时键/值存储?

Jar*_*ock 13 c++ template-meta-programming

我有一个问题,我需要在编译时将一个整数映射到另一个整数.基本上,我需要编译时相当于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 = ...
};
Run Code Online (Sandbox Code Playgroud)

lookup返回与相关联的值keyStaticMap.如果key未找到,则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;
}
Run Code Online (Sandbox Code Playgroud)

n. *_* m. 14

在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;
}
Run Code Online (Sandbox Code Playgroud)

  • @karliwson在默认实例化中粘贴静态断​​言,并删除第一个参数 (2认同)

jda*_*dls 7

您可以使用模板专业化

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
Run Code Online (Sandbox Code Playgroud)

您可以利用一些宏来简化内容的定义。


Jos*_*ley 5

这样的事情会起作用:

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;
}
Run Code Online (Sandbox Code Playgroud)

0是默认值,键1给出值3。根据需要添加其他特殊化。

这是您要寻找的一般想法吗?尽管预处理器宏(例如Boost.Preprocessor)可以简化并简化设置,但它不是您请求的接口。