2

I need to do a mapping between two sets of enums. The correspondence between enums is one to one.

For example

The first set:

Enum1{A, B, C, D};
Enumx...
Enumy...

The second set:

Enum2{A2, B2, C2, D2};
Enumx2...
Enumy2...

The map function:

Enum1 map(Enum2);
Enumx map(Enumx2);
Enumy map(Enumy2);

I'm searching for an elegant manner of doing this map. Can I use template specialization? or the enums are seen all as integers?

Example:

class MapHelper{
public:
    template<typename From, To>
    static To map(From from);

    template<>
    static Enum1 map<Enum2, Enum1>(Enum2 from){
    return static_cast<Enum1>(from);
    }
};
skypjack
  • 49,335
  • 19
  • 95
  • 187
yonutix
  • 1,964
  • 1
  • 22
  • 51

4 Answers4

1

In addition to the static casting that you've now added to your question, you can make the mapping easier / more explicit by setting the values in equivalent enums using the values from a previous enum:-

enum Enum1
{
    a = 1,
    b = 2,
};

enum Enum2
{
    z = a,
    y = b
};

And a way to collapse template into only needing to specify target...

template <typename targettype>
class Converter
{
    public:
    template<typename sourceType>
    static targettype Convert(sourceType from)
    {
        return static_cast<targettype>(from);
    }
};

callable as:-

Converter<Enum2>::Convert(someEnum1);
ROX
  • 1,256
  • 8
  • 18
  • This is not an option due to project restrictions – yonutix Sep 22 '16 at 09:57
  • what kind of restriction would prevent this? – ROX Sep 22 '16 at 10:05
  • Enum1 and Enum2 are in separate files, in Enum2 I don't have acess to Enum1 in order to access Enum1::a. – yonutix Sep 22 '16 at 10:06
  • OK, although separate files would still be OK if you could include the definition of enum1 into the file that defines enum2. If not, then fair enough, but it saves having to separately define the mapping for each value if you can include it. – ROX Sep 22 '16 at 10:19
1

You can use traits:

template<Enum1 V> struct ToEnum2;
template<> struct ToEnum2<Enum1::A> { static constexpr Enum2 value = Enum2::A; };
template<> struct ToEnum2<Enum1::B> { static constexpr Enum2 value = Enum2::B; };
// ...

Then, whenever you have a value from Enum1, you can find the one from Enum2 using:

Enum1<VALUE>::value;

It follows a minimal, working example:

enum class Enum1 { A, B };
enum class Enum2 { C, D };

template<Enum1 E> struct Map;
template<> struct Map<Enum1::A> { static constexpr Enum2 value = Enum2::C; };
template<> struct Map<Enum1::B> { static constexpr Enum2 value = Enum2::D; };

int main() {
    static_assert(Map<Enum1::A>::value == Enum2::C, "!");
    static_assert(Map<Enum1::B>::value == Enum2::D, "!");
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
1

Assuming your enum have same values, You may do:

template <typename E> struct MappingEnum;

template <typename E>
using MappingEnum_t = typename MappingEnum<E>::type;

template <> struct MappingEnum<Enum1>
{
    using type = Enum2;
};

And then

template <typename E>
MappingEnum_t<T> map(E e) { return static_cast<MappingEnum_t<T>>(e); }
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I would say same vaues and direct mapping, the first one from the first enum with the first one from the second enum and so on. One could actually argue about the utility of having those two enums... Uhm... – skypjack Sep 22 '16 at 11:36
0

C++11 solution:

#include <type_traits>

template<typename From, typename To>
To map(From e) {
    return static_cast<To>(
        static_cast<typename std::underlying_type<To>::type>(
        static_cast<typename std::underlying_type<From>::type>(e)));
}

This casting cascade is very explicit and supports enum classes.

For older C++ versions and for enums without class, static_cast<Enum2>(e) would suffice.

Edit:

With template specialization, you can use map without specifying any types explicitly:

enum class Enum1: int {A, B, C, D};
enum class Enum2: char {A1, B1, C1, D1};

template<typename T>
struct target_enum {
};

template<>
struct target_enum<Enum1> {
    typedef Enum2 type;
};

template<typename From>
typename target_enum<From>::type map(From e) {
    typedef typename target_enum<From>::type To;
    return static_cast<To>(
        static_cast<typename std::underlying_type<To>::type>(
        static_cast<typename std::underlying_type<From>::type>(e)));
}

You can then call map(Enum1::A). Also works with simple, non-class enums.

flyx
  • 35,506
  • 7
  • 89
  • 126
  • Yes, but I have to specify always map, I would like to do only map and To type to be somehow in a hashmap like hashmap[From] = To. – yonutix Sep 22 '16 at 09:56