简体   繁体   中英

Enum mapping in C++

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);
    }
};

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, "!");
}

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); }

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.

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM