编译时间映射和反向映射值

pre*_*eys 17 c++ meta templates map inverse

有人可以推荐一种更优雅的方式来实现这些编译时常量吗?

template <int> struct Map;
template <> struct Map<0> {static const int value = 4;};
template <> struct Map<1> {static const int value = 8;};
template <> struct Map<2> {static const int value = 15;};

template <int> struct MapInverse;
template <> struct MapInverse<4> {static const int value = 0;};
template <> struct MapInverse<8> {static const int value = 1;};
template <> struct MapInverse<15> {static const int value = 2;};
Run Code Online (Sandbox Code Playgroud)

这个值需要在我的程序中是constexpr,但逆映射值更新很繁琐(容易出错或忘记做).

zch*_*zch 16

在这个C++ 11解决方案中,所有映射项都保存在constexpr数组中,并且有constexpr递归函数可以按键或值进行搜索.

#include <utility>

using Item = std::pair<int, int>;
constexpr Item map_items[] = {
    { 6, 7 },
    { 10, 12 },
    { 300, 5000 },
};
constexpr auto map_size = sizeof map_items/sizeof map_items[0];

static constexpr int findValue(int key, int range = map_size) {
    return
            (range == 0) ? throw "Key not present":
            (map_items[range - 1].first == key) ? map_items[range - 1].second:
            findValue(key, range - 1);
};

static constexpr int findKey(int value, int range = map_size) {
    return
            (range == 0) ? throw "Value not present":
            (map_items[range - 1].second == value) ? map_items[range - 1].first:
            findKey(value, range - 1);
};

static_assert(findKey(findValue(10)) == 10, "should be inverse");
Run Code Online (Sandbox Code Playgroud)


Ale*_* C. 5

我会使用一个宏:

template <int> struct Map;
template <int> struct MapInverse;

#define MAP_ENTRY(i, j) \
    template <> struct Map<i> {static const int value = j;}; \
    template <> struct MapInverse<j> {static const int value = i;};

MAP_ENTRY (0, 4)
MAP_ENTRY (1, 8)
MAP_ENTRY (2, 15)
Run Code Online (Sandbox Code Playgroud)

这使两个地图保持同步.


H W*_*ers 5

使用 C++11 进行线性搜索的另一种 TMP 方法:

#include <type_traits>

// === Types:
// Usage:
//    Function<Map<x1,y1>,Map<x2,y2>,...>
template<int D, int R> struct Map { enum { domain=D, range=R }; };
template<typename ...A> struct Function {};

// === Metafunctions:
// Usage:
//    ApplyFunction<x,F>::value
template<int I, typename M> struct ApplyFunction;
// Usage:
//    ApplyFunctionInverse<x,F>::value
template<int I, typename M> struct ApplyFunctionInverse;

// ==== Example:
// Define function M to the mapping in your original post.
typedef Function<Map<0,4>,Map<1,8>,Map<2,15>> M;

// ==== Implementation details
template<typename T> struct Identity { typedef T type; };
template<int I, typename A, typename ...B> struct ApplyFunction<I, Function<A,B...> > {
   typedef typename
      std::conditional <I==A::domain
                       , Identity<A>
                       , ApplyFunction<I,Function<B...>> >::type meta;
   typedef typename meta::type type;
   enum { value = type::range };
};
template<int I, typename A> struct ApplyFunction<I, Function<A>> {
   typedef typename
       std::conditional <I==A::domain
                        , Identity<A>
                        , void>::type meta;
   typedef typename meta::type type;
   enum { value = type::range };
};
// Linear search by range
template<int I, typename A> struct ApplyFunctionInverse<I, Function<A>> {
   typedef typename
       std::conditional <I==A::range
                        , Identity<A>
                        , void>::type meta;
   typedef typename meta::type type;
   enum { value = type::domain };
};
template<int I, typename A, typename ...B> struct ApplyFunctionInverse<I, Function<A,B...> > {
   typedef typename
       std::conditional <I==A::range
                        , Identity<A>
                        , ApplyFunctionInverse<I,Function<B...>> >::type meta;
   typedef typename meta::type type;
   enum { value = type::domain };
};

// ==============================
// Demonstration
#include <iostream>
int main()
{
   // Applying function M
   std::cout << ApplyFunction<0,M>::value << std::endl;
   std::cout << ApplyFunction<1,M>::value << std::endl;
   std::cout << ApplyFunction<2,M>::value << std::endl;

   // Applying function inverse M
   std::cout << ApplyFunctionInverse<4,M>::value << std::endl;
   std::cout << ApplyFunctionInverse<8,M>::value << std::endl;
   std::cout << ApplyFunctionInverse<15,M>::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

对于这个应用程序,我更喜欢 zch 的 C++11 解决方案,但也许有人会发现这种方法的价值。