Can we "wrap" templated classes with non-templated classes in C++? - c++

Disclaimer: I am afraid the short answer to my question is "not possible". But since I am not a C++ expert, I thought I still give it a try and ask here, maybe there is some kind of solution which I am just not aware of.
So I have templated container-like class MyContainer that internally stores data in a std::list<T>, where T is the class template type. This works fine.
Now I want to add another class, which has to map instances of that templated container class in a std::map<std::string, MyContainer>. However, the compiler asks me to provide the template class type for the value-part of the map, as in std::map<std::string, MyContainer<T>>. But I would rather omit this template here, since that would in turn require me to use templates for the wrapper class as well.
Thus my question: Is there a way to achieve what I am trying to do, omitting the template type for the wrapper class, at least to some extend? Or is this just not possible in C++, because the compiler needs that information in any case?

One common technique for doing this is inheritance.
You make MyContainer<T> inherit from some base class, such as MyBaseContainer. MyBaseContainer is not a template class, but MyContainer is. The MyBaseContainer class has virtual functions that the templated class overrides.
Then, you make your map of type std::map<std::string, MyBaseContainer*>. It will be able to call the virtual functions on the containers it stores, without having to know the template type of each one.
This is how std::function works.

This is possible but a bit tricky. If i understand you correctly you want each MyContainer class stored inside map to possibly have different template specialization (say some will hold std::list<int> while other will hold std::list<string>) then you value type for map can no longer be just MyContainer but rather class that could hold both list<int> and list<string>.
One way to do it to use inheritance as #IanPudney already pointed out.
However you can do this even without creating inheritance hierarchy for MyContainer classes if you instead declare map as map<string, boost::any> (see http://www.boost.org/doc/libs/1_61_0/doc/html/boost/any.html) that way you will be able to store any kind of MyContainer inside this map without the need to create inheritance hierarchy in advance.

There are two possible ways to do this without using inheritance but this may also depend on a few deciding factors. The first question is: Upon creating an instance of the outside class is the type of the template container known. If it is then this is an easy class to write. If it is not then it can still be done but there would be more work involved. If case is not known there are 2 ways to do this and the first is the one you are trying to avoid by not making this a class template. The second involves more work which some of the logic on how to define this class will be shown.
Pseudo Code: -- 1st Case Where Type Is Known Upon Creation
#include <map>
template<class T>
class MyContainer {
// ... Class Variables, Constructors & Methods
}
// For Demonstration We will say that `T` is known to be an int upon instantiation
class MyClass {
private:
std::map< std::string, MyContainer<int> > maps_;
public:
MyClass() {}
~MyClass() {
// Clear Out Map
}
void addItem( std::string& str, int value ) {
maps_.insert( std::make_pair( str, MyContainer<int>( value ) );
}
};
Now for the 2nd case where the type is not known using the method without templating the wrapper you will need to know of all of the types that this class can support and you will need to create typedef of each of these.
Pseudo Code -- 2nd Case Where Type Is Not Known:
#include <map>
template<class T>
class MyContainer {
// ... Class Variables, Constructors & Methods
}
// For Demonstration We will say that `T` is unknown before instantiation
class MyClass {
public:
typedef MyContainer<int> INTS;
typedef MyContainer<float> FLOATS;
typedef MyContainer<double> DOUBLES;
// And Do This For Every Type This Class Will Support.
private:
std::map< std::string, INTS > mapInts_;
std::map< std::string, FLOATS > mapFloats_;
std::map< std::string, DOUBLES > mapDoubles_;
// And You Will Need A Container For Each Supporting Type
public:
MyClass() {}
// If You Have Constructors Other Than Default That Excepts Parameter Types
// You Will Need A Constructor For Each Supporting Type
~MyClass() {
// Clear Out All Maps
}
void addInts( std::string& str, MyClass::INTS );
void addFloats( std::string& str, MyClass::FLOATS );
void addDoubles( std::string& str, MyClass::DOUBLES );
// And You Will Need A Corresponding Function For Each Type This Class Supports.
};

Related

How to pass a container of derived type to a function needing a container of base type [duplicate]

Consider these classes.
class Base
{
...
};
class Derived : public Base
{
...
};
this function
void BaseFoo( std::vector<Base*>vec )
{
...
}
And finally my vector
std::vector<Derived*>derived;
I want to pass derived to function BaseFoo, but the compiler doesn't let me. How do I solve this, without copying the whole vector to a std::vector<Base*>?
vector<Base*> and vector<Derived*> are unrelated types, so you can't do this. This is explained in the C++ FAQ here.
You need to change your variable from a vector<Derived*> to a vector<Base*> and insert Derived objects into it.
Also, to avoid copying the vector unnecessarily, you should pass it by const-reference, not by value:
void BaseFoo( const std::vector<Base*>& vec )
{
...
}
Finally, to avoid memory leaks, and make your code exception-safe, consider using a container designed to handle heap-allocated objects, e.g:
#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;
Alternatively, change the vector to hold a smart pointer instead of using raw pointers:
#include <memory>
std::vector< std::shared_ptr<Base*> > vec;
or
#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;
In each case, you would need to modify your BaseFoo function accordingly.
Instead of passing the container object (vector<>), pass in begin and end iterators like the rest of the STL algorithms. The function that receives them will be templated, and it won't matter if you pass in Derived* or Base*.
This problem occurs in programming languages that have mutable containers. You cannot pass around a mutable bag of apples as a bag of fruit because you cannot be sure that someone else does not put a lemon into that bag of fruit, after which it no longer qualifies as a bag of apples. If the bag of apples were not mutable, passing it around as a bag of fruit would be fine. Search for covariance/contravariance.
one option is to use a template
template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
...
}
The drawback is that the implementation has to be in the header and you will get a little code bloat. You will wind up with different functions being instantiated for each type, but the code stays the same. Depending on the use case it's a quick and dirty solution.
Edit, I should note the reason we need a template here is because we are trying to write the same code for unrelated types as noted by several other posters. Templates allow you do solve these exact problems. I also updated it to use a const reference. You should also pass "heavy" objects like a vector by const reference when you don't need a copy, which is basically always.
Generally you would start with a container of base pointers, not the other way.
If you dealing with a third-party library, and this is your only hope, then you can do this:
BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));
Otherwise fix your code with one of the other suggesstions.
Taking Matt Price's answer from above, given that you know in advance what types you want to use with your function, you can declare the function template in the header file, and then add explicit instantiations for those types:
// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
...
}
// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
If std::vector supported what you're asking for, then it would be possible to defeat the C++ type system without using any casts (edit: ChrisN's link to the C++ FAQ Lite talks about the same issue):
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
void pushStuff(std::vector<Base*>& vec) {
vec.push_back(new Derived2);
vec.push_back(new Base);
}
...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!
Since your BaseFoo() function takes the vector by value, it cannot modify the original vector that you passed in, so what I wrote would not be possible. But if it takes a non-const reference and you use reinterpret_cast<std::vector<Base*>&>() to pass your std::vector<Derived*>, you might not get the result that you want, and your program might crash.
Java arrays support covariant subtyping, and this requires Java to do a runtime type check every time you store a value in an array. This too is undesirable.
They are unrelated types -- you can't.

Using a template class in STL containers

If I have a template class, that I want to instantiate with different data types:
template <typename T>
class A {
T value;
// ...
};
And I also want to use the objects of this class in a Standard Template Library container (say vector).
In my understanding creating a vector of A objects would not be accepted by the compiler, because A<int> and A<char> are actually different types and I can't put them in the same vector.
The workaround I found was creating a base class, a derived template class, and a vector of base class pointers.
class ABase {
// ...
};
template <typename T>
class ADerived : public ABase{
T value;
// ...
};
std::vector<BaseA*> mySuperVector;
I am starting to experiment with templates to gain a better understanding and I am wondering whether there are better solutions for this. My workaround above gives me also headache, because I am afraid that typecasting will be inevitable at some point.
Templates are a compile-time code generation construct. If you need an heterogeneous container of objects at compile-time, then you can use std::tuple:
std::tuple my_tuple{A<int>{}, A<char>{}, A<double>{}};
If you need an heterogeneous container of objects at run-time, you do need some sort of polymorphism. Using a base class with virtual methods is a valid option. If you know all the possible choice of types your object can be in advance, you can also use std::variant:
using my_a = std::variant<A<int>, A<char>, A<double>>;
std::vector<my_a> vec;
In this case, my_a can either be A<int>, A<char>, or A<double> at any given time. The active alternative can change at run-time.
Needing to typecast to the derived type is not related to the derived type being the instantiation of a class template, it's a design issue. Maybe you need virtual functions or multiple containers instead.
Otherwise, your solution is fine, but do switch to std::unique_ptr if the container is supposed to own the contained objects.

How to create user defined type template class object C++

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 to share different objects between some classes

what is the best way to share different objects between some classes in a generic manner?
For example class A can store an object o with a string as a key in a register and class B can access it using the key.
My first idea was to create a register (singleton) which has a hashtable as a member using a string as the key and a void pointer as the value. But there must be a better solution for this?
From your clarification:
template <typename OB>
class A {
std::unordered_map<std::string, OB> hash;
public:
OB const& get(std::string const&) const;
void add(OB const& object, std::string const&);
};
That is to say, A<int> is a class that stores int objects by name, and A<std::set<float>> is a class that stores sets of floats by name. You can't mix them. That's in line with the basic C++ philosophy: the type of theA.get("foo") is determined at compile time, not by what you put in at runtime.
In C++, you can however "mix" multiple derived types, if you'd need this for your particular case. That's a bit more complicated:
template <typename Base>
class A {
std::unordered_map<std::string, std::unique_ptr<Base>> hash;
public:
Base const& get(std::string const&) const;
template<typename Derived> void add(std::string const& name, Derived const& object)
{
std::unique_ptr<Base> copy(new Derived(object));
hash.emplace(std::make_pair(name, std::move(copy)));
}
};
There's some slight trickery here as hash should be the only owner of the copy, but it's constructed outside and therefore needs to be moved it. (For extra-fancy, I could add a Derived&& overload that eliminates that copy too)
I would suggest that all the classes that you must register have a common supertype.
For instance, if you have to store instances of classes One, Two, and Three you could define a (possibly empty) class Object from which your class can derive:
class Object {}
class One : public Object { /* One's member and methods */ }
class Two : public Object { /* Two's member and methods */ }
class Three : public Object { /* Three's member and methods */ }
If you follow MSalters question you can then declare a A<Object*>.
If you cannot have one supertype (for instance because you cannot change One, Two or Three) you may look at Boost.Variant. Again, you can declare a A<boost::variant<One, Two, Three> >.
The first question is: how does B know the type of the stored object,
and what it can do with it? Perhaps the simplest solution is just to
have one registry per type. Alternatively, something like
boost::variant can be used, or you can ensure that all types derive
from a common base, and store a pointer to that. Unless you actually
need to support polymorphism (e.g. operating on an object without
knowing its exact type), I'd avoid the pointer solution, however.
The best way is to use a shared_ptr, instead of a naked pointer. If you have a C++11 compliant compiler, shared_ptr is in the std namespace. Otherwise, use the Boost implementation.

Getting a vector<Derived*> into a function that expects a vector<Base*>

Consider these classes.
class Base
{
...
};
class Derived : public Base
{
...
};
this function
void BaseFoo( std::vector<Base*>vec )
{
...
}
And finally my vector
std::vector<Derived*>derived;
I want to pass derived to function BaseFoo, but the compiler doesn't let me. How do I solve this, without copying the whole vector to a std::vector<Base*>?
vector<Base*> and vector<Derived*> are unrelated types, so you can't do this. This is explained in the C++ FAQ here.
You need to change your variable from a vector<Derived*> to a vector<Base*> and insert Derived objects into it.
Also, to avoid copying the vector unnecessarily, you should pass it by const-reference, not by value:
void BaseFoo( const std::vector<Base*>& vec )
{
...
}
Finally, to avoid memory leaks, and make your code exception-safe, consider using a container designed to handle heap-allocated objects, e.g:
#include <boost/ptr_container/ptr_vector.hpp>
boost::ptr_vector<Base> vec;
Alternatively, change the vector to hold a smart pointer instead of using raw pointers:
#include <memory>
std::vector< std::shared_ptr<Base*> > vec;
or
#include <boost/shared_ptr.hpp>
std::vector< boost::shared_ptr<Base*> > vec;
In each case, you would need to modify your BaseFoo function accordingly.
Instead of passing the container object (vector<>), pass in begin and end iterators like the rest of the STL algorithms. The function that receives them will be templated, and it won't matter if you pass in Derived* or Base*.
This problem occurs in programming languages that have mutable containers. You cannot pass around a mutable bag of apples as a bag of fruit because you cannot be sure that someone else does not put a lemon into that bag of fruit, after which it no longer qualifies as a bag of apples. If the bag of apples were not mutable, passing it around as a bag of fruit would be fine. Search for covariance/contravariance.
one option is to use a template
template<typename T>
void BaseFoo( const std::vector<T*>& vec)
{
...
}
The drawback is that the implementation has to be in the header and you will get a little code bloat. You will wind up with different functions being instantiated for each type, but the code stays the same. Depending on the use case it's a quick and dirty solution.
Edit, I should note the reason we need a template here is because we are trying to write the same code for unrelated types as noted by several other posters. Templates allow you do solve these exact problems. I also updated it to use a const reference. You should also pass "heavy" objects like a vector by const reference when you don't need a copy, which is basically always.
Generally you would start with a container of base pointers, not the other way.
If you dealing with a third-party library, and this is your only hope, then you can do this:
BaseFoo (*reinterpret_cast<std::vector<Base *> *>(&derived));
Otherwise fix your code with one of the other suggesstions.
Taking Matt Price's answer from above, given that you know in advance what types you want to use with your function, you can declare the function template in the header file, and then add explicit instantiations for those types:
// BaseFoo.h
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
// BaseFoo.cpp
template<typename T>
void BaseFoo( const std::vector<T*>& vec);
{
...
}
// Explicit instantiation means no need for definition in the header file.
template void BaseFoo<Base> ( const std::vector<Base*>& vec );
template void BaseFoo<Derived> ( const std::vector<Derived*>& vec );
If std::vector supported what you're asking for, then it would be possible to defeat the C++ type system without using any casts (edit: ChrisN's link to the C++ FAQ Lite talks about the same issue):
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
void pushStuff(std::vector<Base*>& vec) {
vec.push_back(new Derived2);
vec.push_back(new Base);
}
...
std::vector<Derived1*> vec;
pushStuff(vec); // Not legal
// Now vec contains a Derived2 and a Base!
Since your BaseFoo() function takes the vector by value, it cannot modify the original vector that you passed in, so what I wrote would not be possible. But if it takes a non-const reference and you use reinterpret_cast<std::vector<Base*>&>() to pass your std::vector<Derived*>, you might not get the result that you want, and your program might crash.
Java arrays support covariant subtyping, and this requires Java to do a runtime type check every time you store a value in an array. This too is undesirable.
They are unrelated types -- you can't.