1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
#include <iostream>
#include <type_traits>
enum Ability {Strength, Intelligence};
enum Skill {Athletics, Acrobatics, Arcana, History, Investigation, Nature, Religion};
template <int KEY, int... RANGE> struct Map {}; // one-to-many map (mapping KEY to RANGE...)
template <int KEY, int FIRST, int... REST>
struct Map<KEY, FIRST, REST...> : Map<KEY, REST...> {
using Base = Map<KEY, REST...>;
enum {key = KEY};
static bool inRange (int value) {return (value == FIRST) ? true : Base::inRange(value);} // returns true only if value is found in REST...
};
template <int KEY, int LAST>
struct Map<KEY, LAST> {
enum {key = KEY};
static bool inRange (int value) {return value == LAST;}
};
template <typename...> struct M {};
using SKILLS = M<
Map<Strength, Athletics>,
Map<Intelligence, Arcana, History, Investigation, Nature, Religion>
>;
template <typename T> struct Identity {using type = T;};
struct NotFound {using type = NotFound; static const int key = -1;};
template <int, typename> struct InverseMap {};
template <int N, typename LAST>
struct InverseMap<N, M<LAST>> {
using meta = typename std::conditional<LAST::inRange(N), Identity<LAST>, NotFound>::type;
using type = typename meta::type;
enum {value = type::key};
};
template <int N, typename FIRST, typename... REST>
struct InverseMap<N, M<FIRST, REST...>> {
using meta = typename std::conditional< FIRST::inRange(N), Identity<FIRST>, InverseMap<N, M<REST...>> >::type;
using type = typename meta::type;
enum {value = type::key};
};
int main() {
std::cout << Investigation << " is mapped from " << InverseMap<Investigation, SKILLS>::value << std::endl;
}
|