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);
    }
};
7
  • How far have you come? What have you tried? What are the specific problems you have had? :) Commented Sep 22, 2016 at 9:34
  • The problem I encountered was that I have to specify also the return type and parametrize the function with two types, I would like to parametrize it with just one and have a map of types behind but I don't know how to do it. Commented Sep 22, 2016 at 9:37
  • Please, can you show us your partial solution? That way we can be sure we talk about the same thing and offer help with the correct problems :) Commented Sep 22, 2016 at 9:46
  • I added an example Commented Sep 22, 2016 at 9:54
  • Are the enums always in sequence, and with the same number of elements in each enum? Commented Sep 22, 2016 at 11:24

4 Answers 4

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, "!");
}
Sign up to request clarification or add additional context in comments.

2 Comments

That's very nice!
@yonutix Traits are quite common in C++. Hoping this answer helps you in solving your real issue.
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);

4 Comments

This is not an option due to project restrictions
what kind of restriction would prevent this?
Enum1 and Enum2 are in separate files, in Enum2 I don't have acess to Enum1 in order to access Enum1::a.
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.
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); }

1 Comment

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...
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.

1 Comment

Yes, but I have to specify always map<From, To>, I would like to do only map<From> and To type to be somehow in a hashmap like hashmap[From] = To.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.