Compile-time map and inverse map values
In this C++11 solution all map items are kept in constexpr
array and there are constexpr
recursive functions to search by either key or value.
#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");
Another TMP approach for a linear search using C++11:
#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;
}
I prefer zch's C++11 solution for this application, but maybe someone will find value in this approach.