(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;
}
...
}
}
Related
I want to return a type from function depending on a boolean flag. The idea was to create instances of a Test class later in the program operating with this traits structure that would hold the actual type. However, now I don't know what the return type of a traits function would be.
class Test {
public:
template <typename T>
class Traits {
public:
typedef T type;
};
...
};
??? Test::Options::traits(){
if(timer){
return Test::Traits<Timeable<Test>>();
} else {
return Test::Traits<Test>();
}
}
A function can only return one specific type.
There is no way in C++ to overload on return type.
You cannot dynamically change the return type of a function.
What you are looking for is runtime polymorphism, while C++ templates are compile-time polymorphism.
How are you going to use the return value? something like if (its type is something) ... else ... ? In this case you can use std::variant (C++17).
Or are you going to just call its methods that will be present in all variants? In this case you can use good old inheritance. Extract a common interface to a pure abstract class (often called "interface" anyway), derive from it all types you'd like to return. Ah, and don't return it by value. You can return e.g. std::unique_ptr<YourInterfaceType> (fits your example though involves dynamic memory allocation), or any other kind of reference
I have a limited set of very different types, from which I want to store instances in a single collection, specifically a map. To this end, I use the type erasure idiom, ie. I have a non-templated base class from which the templated, type specific class inherits:
struct concept
{
virtual std::unique_ptr<concept> copy() = 0; // example member function
};
template <typename T>
struct model : concept
{
T value;
std::unique_ptr<concept> copy() override { ... }
}
I then store unique_ptrs to concept in my map. To retrieve the value, I have a templated function which does a dynamic cast to the specified type.
template <typename T>
void get(concept& c, T& out) {
auto model = dynamic_cast<model<T>>(&c);
if (model == nullptr) throw "error, wrong type";
out = model->value;
}
What I don't like about this solution is, that specifying a wrong T is only detected at runtime. I'd really really like this to be done at compile time.
My options are as I see the following, but I don't think they can help here:
Using ad hoc polymorphism by specifying free functions with each type as an overload, or a template function, but I do not know where to store the result.
Using CRTP won't work, because then the base class would need to be templated.
Conceptually I would need a virtual function which takes an instance of a class where the result will be stored. However since my types are fundamentally different, this class would need to be templated, which does not work with virtual.
Anyways, I'm not even sure if this is logically possible, but I would be very glad if there was a way to do this.
For a limited set of types, your best option is variant. You can operate on a variant most easily by specifying what action you would take for every single variant, and then it can operate on a variant correctly. Something along these lines:
std::unordered_map<std::string, std::variant<Foo, Bar>> m;
m["a_foo"] = Foo{};
m["a_bar"] = Bar{};
for (auto& e : m) {
std::visit(overloaded([] (Foo&) { std::cerr << "a foo\n"; }
[] (Bar&) { std::cerr << "a bar\n"; },
e.second);
}
std::variant is c++17 but is often available in the experimental namespace beforehand, you can also use the version from boost. See here for the definition of overloaded: http://en.cppreference.com/w/cpp/utility/variant/visit (just a small utility the standard library unfortunately doesn't provide).
Of course, if you are expecting that a certain key maps to a particular type, and want to throw an error if it doesn't, well, there is no way to handle that at compile time still. But this does let you write visitors that do the thing you want for each type in the variant, similar to a virtual in a sense but without needing to actually have a common interface or base class.
You cannot do compile-time type checking for an erased type. That goes against the whole point of type erasure in the first place.
However, you can get an equivalent level of safety by providing an invariant guarantee that the erased type will match the expected type.
Obviously, wether that's feasible or not depends on your design at a higher level.
Here's an example:
class concept {
public:
virtual ~concept() {}
};
template<typename T>
struct model : public concept {
T value;
};
class Holder {
public:
template<typename T>
void addModel() {
map.emplace(std::type_index(typeid(T)), std::make_unique<model<T><());
}
template<typename T>
T getValue() {
auto found = types.find(std::type_index(typeid(T)));
if(found == types.end()) {
throw std::runtime_error("type not found");
}
// no need to dynamic cast here. The invariant is covering us.
return static_cast<model<T>*>(found->second.get())->value;
}
private:
// invariant: map[type] is always a model<type>
std::map<std::type_index, std::unique_ptr<concept>> types;
};
The strong encapsulation here provides a level of safety almost equivalent to a compile-time check, since map insertions are aggressively protected to maintain the invariant.
Again, this might not work with your design, but it's a way of handling that situation.
Your runtime check occurs at the point where you exit type erasure.
If you want to compile time check the operation, move it within the type erased boundaries, or export enough information to type erase later.
So enumerate the types, like std variant. Or enumerate the algorithms, like you did copy. You can even mix it, like a variant of various type erased sub-algorithms for the various kinds of type stored.
This does not support any algorithm on any type polymorphism; one of the two must be enumerated for things to resolve at compile time and not have a runtime check.
I need to create a class that stores multiple User defined types. It should return one of them, on demand. Is there a way to implement one function to return all the types?
Please note: I cannot use Boost libraries. I need to implement in Visual Studio
class One {};
class Two {};
class Three {};
enum Type
{
OneType,
TwoType,
ThreeType
};
class GenericType
{
template <typename T> // --- How to implement this function
T getValue(Type type)
{
switch(type)
{
case One: return oneType; // Error
case Two: return twoType;
case Three: return threeType;
}
}
shared_ptr<OneType> oneType;
shared_ptr<TwoType> twoType;
shared_ptr<ThreeType> threeType;
Type m_type;
};
In C++11 you have an std::tuple class that does the job. You can retrieve needed element with std::get, like this:
// Create a tuple
std::tuple<std::shared_ptr<OneType>, std::shared_ptr<TwoType>> tuple{null, null};
// Get element
std::get<std::shared_ptr<OneType>>(tuple)
This declaration,
template <typename T> // --- How to implement this function
T getValue(Type type)
… where Type is an enum, makes the run time choice of argument determine the compile time choice of function result type, or alternatively requires the run time selection of argument value to be compatible with the compile time choice of type.
The former is backward in time, so it's not on, and the latter is just silly.
If an ordinary function template is OK for you, then the solution is simple: specialize it for each relevant type.
If you need to have run time selection, then instead use a common result wrapper type. For value semantics it can be a class with union members, i.e. a discriminated union. For reference semantics it can be a pointer to a common base class of the possible result types.
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.
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.