I want to instantiate a template class with data types that are available at runtime in variables. For example, consider this class:
template <typename T, unsigned int U>
class Allocator
{
public:
T * pointer;
Allocator() { pointer = new T[U]; }
~Allocator() { delete [] pointer; }
};
Now I want to use it like this:
int main()
{
string temp = "int";
unsigned int count = 64;
Allocator<temp, count> a;
return 0;
}
Is there any way of doing this?
I am facing this problem in the context of serializing derived classes with base pointers. I use RTTI to identify the real type of derived class, but the information of the real type is stored in a string. My problem is to be able to dynamic_cast to the type (available as a string at runtime) from the base pointer. Please help.
You can't. Data types must be known at compile time. Maybe using Boost or unions may solve the problem in a non-pretty way.
Good luck!
The absence of a reflection mechanism in C++ makes practically impossible the "dynamic creation" based on data with a direct language support.
The only way is to use a "switch", or any equivalent declarative mechanism, like a factory class owning a dispatch map that associate the strings declaring the type to creation function calls.
Related
(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);
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.
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;
}
...
}
}
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
a particularly powerful technique is having the derived classes be type-specific instantiations of the same template, as it means you can support arbitrary types parametrically, i.e. if they provide the semantics of usage that the template expects
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_wrappers 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.
I won't steal the answer, but I will provide the method I ended up using for those who are trying to do something similar. (I am writing my own raw serialization and deserialization code with memcpy.) What I had hoped to do was store and maintain various arrangements of types without having to create a bunch of structs or classes, e.g. (from my question):
template <typename T>
class ClassThing
{
public:
T Value;
SupportedTypes Type;
}
//Then store everything in a:
vector<ClassThing> things;
However, attempting to store a templated class in a vector will give an "argument list for class template ... is missing" error, because as Tony D said in his answer, "You can't create even a single object from a template without instantiating it..." I also didn't want to use any external libraries like boost (for variants).
So, I concluded that because I absolutely wanted to use a single collection to store all of the structures, I simply could not use a templated class. Instead, I resolved to use a templated constructor (only) and a void* for the Value, as well as store the type's hash and the number of bytes required for storing/copying the type:
class ClassThing
{
public:
void* Value;
unsigned long long TypeHash;
unsigned long long NumberOfBytes;
template <typename T>
ClassThing(T passedValue)
{
Value = &passedValue;
TypeHash = typeid(passedValue).hash_code();
NumberOfBytes = sizeof(T);
}
//For strings, do this:
ClassThing(const char* passedValue, unsigned short passedNumberOfBytes)
{
Value = const_cast<char*>(passedValue);
TypeHash = typeid(char*).hash_code();
NumberOfBytes = length;
}
}
Unfortunately, this solution loses the type, but since the serialization and deserialization process I'm using is a simple memcpy, all I needed was a pointer to the data and the number of bytes it used. The reason I store the type's hash here is so that I can perform type checking before serialization (e.g. make sure a float isn't being serialized where an int should be).
For the deserialization process, I will be using this technique: https://stackoverflow.com/a/15313677/1599699
Since I do not know the type, I will simply have to expect that the cast from void* matches up with the serialization process, although I can at least check the NumberOfBytes value and ideally the TypeHash as well, if those are available. On the deserialization end, I will end up with a void* and do this:
void* deserializedData = ...;
float deserializedFloat = *(float*)&deserializedData;
This of course is not the ideal solution to my problem, but it allows me to do what I want, which is extremely high performance serialization and deserialization to binary with low memory usage and extremely low maintenance.
Hope this helps someone!
Although this is not exactly a C++ answer (rather, a C one), it should be valid in C++ all the same.
The type void* is a pointer to untyped memory. Basically, you can cast it to any type of pointer, then dereference. Example:
int x1 = 42;
long l1 = 123456789L;
void* test = &x1;
int x2 = *(int*)test; // x2 now contains the contents of x1
test = &l1;
long l2 = *(long*)test; // l2 now contains the contents of l1
This is in no way the most delicate way of solving your problem, but it is an option.
Further reading:
https://www.astro.umd.edu/~dcr/Courses/ASTR615/intro_C/node15.html
http://www.circuitstoday.com/void-pointers-in-c
http://www.nongnu.org/c-prog-book/online/x658.html
If you want dynamic types (in C++11 or better, e.g. C++14) you could make a variant type by making a class with some union:
class Thing {
enum SupportedTypes type;
union {
intptr_t num; // when type == IntType
double flo; // when type == FloatType
std::string str; // when type == StringType
}
// etc....
};
Be careful, you need to obey to the rule of five and you probably should explicitly call the destructor of std::string on str when type == StringType, etc...
Some third party libraries might be helpful: Boost variants, Qt QVariant, etc...
I am struggling with allowing user to select data type template will be created as.
Since template type must be defined on compile, I must specify data type template will use eg(string,int, so on), but that means I cannot change it latter on, from lets say string to int even if my template supports it, because template class object was declared as string.
My class declaration below:
template <class T>
class MyHashTable
{
public:
string deleted="deleted";
unsigned short tableSize;
// array of vectors, hash table container
vector<T>* myTable;
vector<T>* deletionTable;
MyHashTable(unsigned short tableSize) : myTable(new vector<T>[tableSize]), deletionTable(new vector<T>[tableSize])
{
this->tableSize=tableSize;
}
object declaration outside class
MyHashTable <string>* myChainedTable=NULL ;
string tableType;
object initialization
if (myChainedTable)
{
delete myChainedTable;
myChainedTable=NULL;
}
getType();
if (!myChainedTable)
{
if (tableType=="string")
myChainedTable= new MyHashTable<string>(length);
if (tableType=="char")
MyHashTable<char> myChainedTable(length); // no difference with or without using new keyword
if (tableType=="double")
MyHashTable<double> myChainedTable(length);
if (tableType=="float")
MyHashTable<float> myChainedTable(length);
if (tableType=="int")
MyHashTable<int> myChainedTable(length);
cout<<tableType<<" table of size "<< length<<" created"<<endl;
I attempted passing class object to functions instead of having it as global variable, but couldnt get it work either.
What I really need is single template object that can have: int,string,char,double,float types, I have 3 functions that need to have access to template class object, and having 5 different objects and 200 lines of if statements for each situation sounds like worst possible solution.
I been stuck on this for a while and just cant figure out how to do it and any help will be appreciated.
void getType()
{
cout<<"Enter table type, types available: int, char, float, double, string.\n";
tableType=getInput();
while((tableType != "int")&&(tableType !="float")&&(tableType !="double")&&(tableType!="char")&&(tableType !="string"))
{
cout<<"Invalid type, please try again "<<endl;;
tableType=getInput();
}
}
Your question is at the boarder between templates and variants.
The template is compile time. So you have to choose at compile time the type you want for your object. Your conditional approach can't work (see comments to question).
On the other side, you seem to need a dynamic choice of type at runtime.
If you want to go on on template way: (edit based on comments)
You'd need to have all the templates inherit from a single polymorphic base class (one common interface with virtual functions). Example:
class MyHashBase // common base class for all templates
{
public:
virtual void addElement(void *ptrelem) = 0; // adding an element must be implemented by template. With void* since future template type unknown from base class
virtual void displayAll() = 0;
};
The templates would need then implement the virtual functions:
template <class T>
class MyHashTable : public MyHashBase
{
public:
unsigned short tableSize;
vector<T>* myTable; // I leave it as it is, but you could implement these as vector<T> instead of vector<T>*
vector<T>* deletionTable;
MyHashTable(unsigned short tableSize) : myTable(new vector<T>[tableSize]), deletionTable(new vector<T>[tableSize]), tableSize(tableSize)
{ }
void addElement(void* ptrelem)
{ myTable->push_back(*reinterpret_cast<T*>(ptrelem)); } // reinterpret the void* of the common interface as a T*
void displayAll()
{ copy(myTable->begin(), myTable->end(), ostream_iterator<T>(cout, "\n")); }
};
You could then have your myChainedTable be a pointer to the common base type, and intialise this pointer in the way you did with the string case (i.e. using new).
MyHashBase *myChainedTable = nullptr;
//...
if (tableType == "string")
myChainedTable = new MyHashTable<string>(length);
else if (tableType == "double")
myChainedTable = new MyHashTable<double>(length);
//...
You could then use the common API, for example if tableType is "double":
double d1 = 3.1415, d2 = 1.4142;
myChainedTable->addElement(&d1); // ATTENTION: you must ensure to provide pointer to the correct data type
myChainedTable->addElement(&d2);
myChainedTable->displayAll();
You'll certainly have a coupe of if required in the calling code, but you could reduce them to minimum by carefully designing the base class (for example, you could add a virtual clone function, to duplicate the data without need to know the type by the caller).
However, using a single signature for the common functions of the base class is cumbersome. To make the virtualisation possible you need to pass parameters through void* pointer which is not so nice and rather error prone.
Alternate way with variants
You could also use boost variants which are meant for managing objects with dynamic definition of types.
In this case you would not need template for your own data structure. You would create a MyHashTable with elements of type boost::variant< int, std::string, ... >.
You could then access to the right value of the object if you know its type (as in your myChainedTable) by using: boost::get<int> (element) (or boost::get<string>(), ...).
If you don't know the type on an element you could use the concept of "visitor" to chose automatically the appropriate function to exectue depending on the type.
Edit: alternate way with unions:
If you're not allowed to use variants another alternative could be use a union. I don't know the topic of you rassignment, but you have the choice whether you use a union to define the elements (like the variants, without templates) or to use a template type as you did, but define myChainedTable to be a union of pointers to the different template instantiations. But yes, it requires a lot of ifs...
Templates are resolved at compile time. Your container type is resolved at runtime. Templates are clearly not the solution here. The first thing that comes to my mind is a combination of boost::any and std::vector instead.
How can I do this way easier:
struct Parameters {
public:
int Parameter1;
std::string Parameter1;
int Parameter2;
std::string Parameter2;
}
Isn't there "var" in C++ like in .NET ? I need parameters to be able to be integers and strings.
You have the key word 'auto' in C++ but it's on C++0x and C++1x, it's the compiler which will decide the type and it can't change after the compilation.
You're probably looking for something like boost::variant: http://www.boost.org/doc/libs/1_56_0/doc/html/variant.html
You can use Union, but you will still need to know at compile time what type you are assigning. You can sort of hide this by using templates with implicit typing to assign values, but you will still have to know the appropriate type when reading the value. Not sure how useful that would be though.
You could also use polymorphism and your own (template) wrapper class in place of the built in types.
I suggest you factor out the common code and set up to use a factory.
Use of a Factory
The problem is that you don't know the type of the parameter until you parse the string. The best method is to keep everything as a string or create a Factory and use a base class. For more research, see "c++ factory design pattern example".
struct Base_Parameter
{
std::string& parameter_as_string;
virtual void extract_parameter(const std::string& parameter_string) = 0;
};
struct Int_Parameter : public Base_Parameter
{
int parameter_value;
void extract_parameter(const std::string& parameter_string)
{
std::istringstream param_stream(parameter_string);
param_stream >> parameter_value;
}
}
Your parameter "list" would be either a container of pointers to the base class (if the types are unknown) or you could have a container of the descendent struct:
struct Parameter_Container
{
std::vector<Int_Parameter> parameters;
};
As for the factory, the factory would be an object that could create parameter objects based on some criteria. It would return a pointer to the base class.
Note: Unless you are on a tightly constrained platform, such as an embedded system, don't worry about overlapping memory locations to save room.
I would like to have a std::hash_map that maps (for instance) regular std:strings to multiple different specializations of another template class.
This example is what I'm trying to achieve (it's wrong and doesn't compile, though):
template<typename T>
class Foo {
public:
Foo(T _value)
{
this-> value = _value;
}
private:
T value;
};
int main()
{
hash_map<string, Foo> various_foos;
various_foos["foo"] = Foo<int>(17);
various_foos["bar"] = Foo<double>(17.4);
}
The map can only store a single value type, so it can't directly store objects of different types; and different specialisations of a class template are different types.
Common solutions are:
Store pointers to a polymorphic base type, and access the real type via virtual functions or RTTI. You will need to be a bit careful about managing the objects themselves - either store smart pointers, or keep them in some other data structure(s).
Store a discriminated union type such as boost::variant or boost::any
You generally can't have an element in your hash that's of an incomplete type. Can you make a non-template base class that the others can inherit from?
The reason for this largely boils down to how the compiler will interpret your request. If it can't compute the size of your Foo structure, it can't create the internals for the hash_map.