I'm aware of c++ templates, which allow you to write code for multiple types, but what if I want to store and access a type dynamically? Why is this so difficult to do in c++?
I would very much prefer to not have to do something like this:
enum SupportedTypes
{
IntType,
FloatType,
StringType
}
template <typename T>
class ClassThing
{
public:
T Value;
SupportedTypes Type;
}
...
//Not sure if you could even access thing->Type, but regardless, you get the idea...
switch (thing->Type)
{
case IntType:
DoSomething(((ClassThing<int>*)thing)->T);
break;
case FloatType:
DoSomething(((ClassThing<float>*)thing)->T);
break;
case StringType:
DoSomething(((ClassThing<string>*)thing)->T);
break;
}
Why doesn't c++ support something like this:
int whatIsThis = 5;
type t = typeid(whatIsThis); //typeid exists, but you can't do...:
t anotherInt = 5;
?
Another question that I have that I'm more optimistic of receiving a good answer to: if you choose to go the templated route, is there any way to maintain the type if you store it generically in a collection? E.g.:
vector<ClassThing> things;
(This will give an "argument list for class template ... is missing" error, by the way.) My guess is that no, this is not possible because the above is not possible.
How do I store and access a type dynamically in c++?
There are many options to pick from:
use runtime polymorphism, where you have a base class that might offer some common functionality and derived classes for each supported type; you often have to make some choices about how "fat" your interface should be (providing base class functions that only work meaningfully for a subset of derived types) vs. forcing the client to use dynamic_cast<>
to recover/switch-on the runtime type
use a discriminated union (basically, a type identification enum
/int
alongside a union of the supported types) - std::variant<>
is a good choice for this
when creating/storing a value capture you'll necessarily know it's type
you can record both its typeinfo
and address, then when accessing the variable later you can use the typeinfo
to test whether the object is of a specific type - trying each supported type until a match is found - std::any<>
is a good choice for this, or
you can capture an arbitrary set of type-specific operations using function pointers or std::function<>
Why doesn't c++ support something like this:
int whatIsThis = 5;
type t = typeid(whatIsThis); //typeid exists, but you can't do...:
t anotherInt = 5;?
It does, with decltype
and auto
:
int whatIsThis = 5;
using t = decltype(whatIsThis);
t anotherInt = 5;
auto anotherWhatever = whatIsThis; // another way to create an additional
// variable of the same type
For runtime polymorphism, you might actually want to read up on factories (which create one of many types of object - all derived from some base interface - given some runtime input), and clone functions (which create a copy of a variable of unknown runtime type).
if you choose to go the templated route, is there any way to maintain the type if you store it generically in a collection:
vector<ClassThing> things;
(This will give an "argument list for class template ... is missing
" error, by the way.)
You can't create even a single object from a template without instantiating it, so no there's no way to have an entire vector
either. A reasonable approach is to derive the template from a base class and store [smart] pointers or std::reference_wrapper
s to the base class in the vector
.
int x = 5;
decltype(x) y = 4;
auto z = 3;
decltype(a)
will give you the type of a
. You can then use typedef
to store the types, or other functions to remove references from the type if necessary.
For example:
typedef decltype(a) type1;
type1 b = 2 * a;
auto
makes you not need to specify the type at all.
The only thing you need is to compile in c++11 mode (-std=c++11
) or later.
As for the vector question, decltype
will work there too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With