Home > other >  C : Create instance of templated class based on enum values
C : Create instance of templated class based on enum values

Time:01-30

(How) is it possible to write a function that instantiates a template class based on input values? For example, given the template class:

template <typename T>
class Container {
  T value;
};

I would need a function like

Container<?> convert(void* value, DataType data_type) {
  switch (data_type) {
    case INT32: {
      Container<int32_t> cnt;
      cnt.value = static_cast<int32_t>(value);
      return cnt;
    }
    ...
  }
}

and use it as follows:

void* value;
DataType data_type; // enum: can be INT32, INT64, ...
do_something(value, &data_type);  // some C function
Container<?> cnt = convert(value, data_type);

CodePudding user response:

You don't need an enum for this. You can just use the type itself:

template <class T>
Container<To> convert(void* value)
{
    Container<T> cnt{};
    cnt.value = *static_cast<T*>(*value);
    return cnt;
}

with usage:

void* value;
do_something(value, &data_type);  // some C function
Container<int32_t> cnt = convert_to<int_32>(value);

The C function I'm using defines this enum and gives me a data type. Is it right that I cannot get around a solution where the user of my (wrapper) function has to know the return type?

Correct. The value of the enum is known at runtime while the template parameter for Container must be known at compile time. So you cannot determine the type of Container from data_type.

There is something you can do though. You can use std::variant, but I don't go into it here.

CodePudding user response:

To achieve this you have to map an enum with a type. Instantiation implies this to happen at runtime, which requires some kind of RTTI, be it built in or self made (e.g using std::type_info::hash_code)

If you say enum this implies a finite, known set of to be expected types. The easiest way is to have a non templated base class from which the templated ones inherit.

class Container_base {};
template <typename T>
class Container : public Container_base {
  T value;
};

Your factory function convert can then cast, or instantiate dynamically base class pointers.

Container_base* convert(void* value, DataType data_type) {
  switch (data_type) {
    case INT32: {
      return new Container<int32_t>; // instantiate new object (some people prefer smart pointers, which may handle ownership stuff like deletion for you, with cost of overhead)
      // return reinterpret_cast<Container<int32_t>*>(value); // alternatively just cast/convert type
      break;
    }
    ...
  }
}

Another implementation might be a mapping table instead of switch (slow) using std::unordered_map, depending on the expected amount of types / likelyhood of types in order, etc.

For usage you might either use the C virtual feature, use CRTP, or implement functionality directly in the template class - matter of favor and use case.

The above approach allows casting and instatiating. Depending on use case, duck typing might be an enhancement.

Unfortunately C does not (yet?) provide us type reflection at runtime.

  •  Tags:  
  • Related