How can I set the type of an object depending of an input value?

152 views Asked by At

I am writing a function that takes the enum MyEnum as input. Depending on the value of MyEnum, I initialize an object and process it. I cannot change the class hierarchy of those objects (their classes), since they are from an external dependency. Processing the newly created object is always the same.

Question:

How can I write this "elegantly". I do not want to write a long if, else if, else block that repeats itself over and over, which is what I currently do. What I would like to have is some magic function that tells me the type to use at runtime. Afaik this does not exist.

What I would like to have:

magic_function(enum_known_at_runtime) my_object;

What I would use if I knew the value at compile time: play with code

enum class MyEnum { A, B , /* many more values */ };

template <MyEnum>
struct get_type;

template <>
struct get_type<MyEnum::A> {
  using Type = unsigned int; // some type
};

...

int main() {
    get_type<enum_known_at_compiletime>::Type i;
    // do stuff with i  
}

What I currently do:

if (enum_known_at_runtime == MyEnum::A) {
    // init an object of some type and do stuff with it
} else if (enum_known_at_runtime == MyEnum::A) {
    // init an object of other type and do same stuff with it
} ...
1

There are 1 answers

1
Botje On

Let us assume you capture the repeated code in a templated function and define corresponding instantiations for get_type:

template <MyEnum E>
struct get_type;

template <MyEnum E>
void init_object_do_stuff() {
    using T = get_type<E>::type;
    T client;
    client.do_stuff();
}

You can now write your repeated code as follows:

switch (enum_known_at_runtime) {
    case MyEnum::A: init_object_do_stuff<MyEnum::A>(); break;
    case MyEnum::B: init_object_do_stuff<MyEnum::B>(); break;
}

Now the work for new enums is adding a single line and an extra case for get_type, which you can further shrink using a macro. As a bonus, the compiler will yell at you if your switch does not cover all cases.