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 the typeid operator, or a std::type_info::hash_code
based on that).
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.
Memory management consideration
Instead of dealing with dynamic memory management using raw pointers
(as in my example above) one might prefer the use of smart pointers
(What is a smart pointer and when should I use one?).
TLDR: smart pointers manage ownership and sharing behavior for you. They delete dynamically created memory for you without the need to care about.
Your example using smart pointers would look like this
std::shared_ptr<Container_base> convert(void* value, DataType data_type) {
switch (data_type) {
case INT32: {
return std::make_shared<Container<int32_t>>();
break;
}
...
}
}