In Java if you have a class like:
class Box<E>
{
some code
}
you can do the following using a wildcard:
Box<?> someBox;
someBox = new Box<Integer>();
someBox = new Box<Double>();
Is there a way to do this in C++?
In better words, how can I declare a variable in C++ that can hold either Box<Integer> or Box<Double> or Box<WhateverDataTypeHere>?
template <typename T> class Box should inherit from a non-template base (let's say class BasicBox).
Then a pointer to BasicBox can point to objects of the specializations of the derived template:
BasicBox *someBox = new Box<int>;
Or, since in modern C++™ manually managing memory should be avoided, using a smart pointer would be a better idea:
std::unique_ptr<BasicBox> someBox = std::make_unique<Box<int>>();
In addition to HolyBlackCat's excellent answer, I should also mention you do have a couple of other options to achieve a similar effect.
If you have some subset of classes, you can inherit them all from the same base like this:
class Base {
};
class Derived1 : public Base {
};
class Derived2 : public Base {
};
Then, you can create a Box like this:
Box<std::uinque_ptr<Base>> genericBox;
genericBox can now hold any derived, though because of the way C++ works, you probably need to hold it by pointer, reference, or std::unique_ptr. Consequently, this is kind of messy, but works.
Also, I should mention that using this method will not work for types like int or double, so this is probably not useful if you need to use those types.
Better is, if you have access to it, to use std::variant. This will allow you to store a specific set of types:
Box<std::variant<int, double>> genericBox;
This genericBox can hold either a double or an int.
If you don't have direct access to std::variant, there is also a boost::variant which is basically the same thing. Or, if you have access to neither, you do have the option of a union:
union GenericType {
int myInterger;
double myDouble;
};
Box<GenericType> genericBox;
Of course, std::variant and boost::variant is better, but this will work for you if you're ever in a situation where you don't have those.
Now, these options will only work if you ever know ahead of time what types you are attempting to store. If you don't know that, you have the option of std::any:
Box<std::any> genericBox;
As with std::variant, there is also a boost::any. You can also implement it yourself if you really have to for some crazy reason. But I wouldn't recommend doing that unless you are doing it for educational purposes or something.
In C++ it's called templating
template <typename T>
class Box {
private:
T boxcontents;
}
replace T with whatever type you want. Here's some great documentation on the topic
Well, this is not something that someone want but you can use a pointer for basic types like int
For classes you can do that or use some base class for all types you may use.
Related
How can I store in a std::vector multiple shared_ptr each one with a pointer to a different type?
std::vector < ? > vec;
vec.push_back( make_shared<int>(3));
vec.push_back( make_shared<float>(3.14f));
Is there a base polymorphic class that can I use for that task without having to use compiler-specific stuff?
There are a few ways you can do this. I assume you want to store various native types, as you're using int and float.
If your list of types is finite, use boost::variant. e.g.
std::vector<std::shared_ptr<boost::variant<int, float>>>;
If you want to store anything, use boost::any. e.g.
std::vector<std::shared_ptr<boost::any>>;
I you really need to do exactly this, use boost::any.
And use std::vector <std::shared_ptr<boost::any> > vec;
You can't mix types like that. You may want to have a look at boost::any
No, C++ does not have a single type from which everything is derived like many other languages do. int and float are native types, meaning they are fundamental to the language and not derived from anything else.
If you have the benefit of Boost, you can store any or variant types in your vector instead.
I need at least 1 shared_ptr to keep resources alive
For this to work, all the types you store must inherit from the same base class, which is the same type as the type contained in the shared pointer. Additionally, the base class must declare a virtual destructor (see this question).
Using boost::any will mean that every other shared_ptr to the objects also has to be a shared_ptr<bsst::any>, which is likely not what you want.
A possible way I figured to solve that is by doing the following
class ISomething{
bool isAlive;
public:
virtual bool alive(){ return isAlive;}
virtual ~ISomething() {}
};
template <typename T>
class Something: public ISomething{
std::shared_ptr<T> myRes;
public:
};
std::vector<ISomething*> myVec; //push back a new dynamic allocation for each "Something"
That's basically type erasure, the same concept behind "Boost::Any" "Poco::Any" "Ogre::Any"
Function1 can be called with any type T which will be converted to (void*) to be able to add to the list but with this I lose the original pointer type (I need t store tham in one linkedlist because I cannot create one for every possible type). So somehow I need to save the type of the pointer as well. I know that it cant be done using c++. Can anyone suggest an alternative solution?
class MyClass
{
template<class T>
void function1(T* arg1)
{
myList.add((void*)arg);
}
void function2()
{
for(int i = 0; i < myList.size(); i++)
{
myList.get(i);
//restore the original pointer type
}
}
STLinkedlist<void*> myList;
}
The usual way to handle these kinds of problems is by using a public interface, in C++ this is done through inheritance. This can be a drag, especially in constrained situations, where a full class/interface hierarchy would provide too much code/runtime overhead.
In comes Boost.Variant, which allows you to use the same object to store different types. If you need even more freedom, use Boost.Any. For a comparison, see e.g. here.
At the end of the day (or better: rather sooner than later), I'd try to do things differently so you don't have this problem. It may well be worth it in the end.
If you lost the type info by going void* it is just gone. You can not just restore it.
So you either must store extra information along with the pointer, then use branching code to cast it back, or rather drive design to avoid the loss.
Your case is pretty suspicious that you do not what you really want.
A more usual case is that you want a polymorphic collection. That doesn't store any kind of pointers but those belonging to the same hierarchy. Collection has Base* pointers, and you can use the objects through Base's interface, all calling the proper virtual function without programmer's interaction. And if you really need to cast to the original type you can do it via dynamic_cast safely. Or add some type info support in the base interface.
Function1 can be called with any type T which will be converted to (void*) to be able to add to the list but with this I lose the original pointer type (I need t store tham in one linkedlist because I cannot create one for every possible type).
You're having the XY problem. The solution is not to decay your pointers to void* and store type information.
You simply can create a type for every possible type - you create a template type. You need to define an abstract interface for your "type for every object", then define a template class implementing this interface, that is particularized by type. Finally, you create your custom-type instance on your type of pointer received and store them by base class pointer (where the base class is your interface definition).
All that said, you (normally) shouldn't need to implement this at all, because the functionality is already implemented in boost::any or boost::variant (you will have to choose one of them).
General
Take into consideration, that if you want to store different objects inside a std::vector<void *>, mostly likely your application has a bad design. In this case, I'd think, whether it is really necessary to do it (or how can it be done in another way), rather than searching for the solution, how to do it.
However, there are no fully evil things in C++ (nor in any other language), so if you are absolutely certain, that this is the only solution, here are three possible ways to solve your problem.
Option 1
If you store only pointers to simple types, store the original type along with the pointer by an enum value or simply a string.
enum DataType
{
intType,
floatType,
doubleType
};
std::vector<std::pair<void *, DataType>> myData;
Option 2
If you store mixed data (classes and simple types), wrap your data in some kind of class.
class BaseData
{
public:
virtual ~BaseData() { }
};
class IntData : public BaseData
{
public:
int myData;
};
std::vector<BaseData *> myData;
Later, you'll be able to check the type of your data using dynamic_cast.
Option 3
If you store only classes, store them simply as a pointer to their base class and dynamic_cast your way out.
You could use boost::any to store any type in your list instead of use void*. It's not exactly what you want but I don't think you can restore the type in run time (as Kerrek said, it's not Java).
class MyClass
{
template<class T>
void function1(T arg1)
{
myList.add(arg);
}
template<class T>
T get(int i)
{
return boost::any_cast<T>(myList.get(i));
}
STLinkedlist<boost::any> myList;
};
If I have a mix-in defined as...
template<class T> class Mixin : public T
{
// mixin methods and members
};
...and declare it with T being a non-polymorphic class...
Mixin<NonPoly> mixin;
..and then have a base class pointer to it...
NonPoly* nonPolyPtr = &mixin;
...how can I later ensure nonPolyPtr is pointing to a Mixin type?
dynamic_cast<Mixin*>(nonPolyPtr)
The above does not compile because the base class is non-polymorphic.
I saw Boost has some trait classes that may help, but I'm hoping there's a simpler solution I'm overlooking.
I think you are looking at the wrong requirements. You don't need to do any casting here, but you may need to do some restructuring of your code. If you have a relationship of classes A, which creates mixin and B which uses NonPoly, then just pass B the NonPoly pointer and use the mixin directly in A. There should be no reason to give up the type information in A just to try to get it back again. If there are more classes, separate them into those who know the mixin and those who know NonPoly, and it's the same relationship.
And it is very likely that if this is the case in the first place, a mixin design is not the proper approach. Very often, mixins are used when simple containment is needed. In my example with A and B above, you may have a Mixin class
template <typename T>
class Mixin
{
T * GetObject()
{ return & t_; }
// other methods that use t_
private:
T t_;
};
and then just pass the object when it needs to be operated on. Or even more common, if you are just passing T to some 3rd party library, you need no mixin at all. Containment might not even be best. The best way to maintain encapsulation is always to write file-scope algorithms when you can manipulate the type T through it's public interface and public 3rd party routines.
If you can explain why you think you need to lose the type information and then later recover, we might be able to show more clearly how you can restructure ownership so that doesn't need to happen, but since this type information never leaves the runtime (since you are looking to cast - your question implies it's not getting serialised or anything), I can assure you that there is some design where that type information is not lost in the first place.
If you are certain of its type just use static_cast to downcast. You also need to specify the template parameter in the cast Mixin<NonPoly>*.
template<class T>
class Mixin : public T
{
// mixin methods and members
};
class NonPoly {
};
int main() {
Mixin<NonPoly> mixin;
NonPoly* nonPolyPtr = &mixin;
Mixin<NonPoly>* mixinPtr = static_cast<Mixin<NonPoly>*>(nonPolyPtr);
}
If I have the following hypothetical class:
namespace System
{
template <class T>
class Container
{
public:
Container() { }
~Container() { }
}
}
If I instantiate two Containers with different T's, say:
Container<int> a;
Container<string> b;
I would like to create vector with pointers to a and b. Since a and b are different types, normally this wouldn't be possible. However, if I did something like:
std::stack<void*> _collection;
void *p = reinterpret_cast<void*>(&a);
void *q = reinterpret_cast<void*>(&b);
_collection.push(a);
_collection.push(b);
Then later on, I can get a and b back from _collection like so:
Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());
My question is, is this the best way for storing a collection of unrelated types? Also would this be the preferred way of storing and retrieving the pointers from the vector (the reinterpret cast)? I've looked around and seen that boost has a nicer way of solving this, Boost::Any, but since this is a learning project I am on I would like to do it myself (Also I have been curious to find a good reason to use a reinterpret_cast correctly).
Consider boost::any or boost::variant if you want to store objects of heterogeneous types.
And before deciding which one to use, have a look at the comparison:
Boost.Variant vs. Boost.Any
Hopefully, it will help you to make the correct decision. Choose one, and any of the container from the standard library to store the objects, std::stack<boost::any>, std::stack<boost::variant>, or any other. Don't write your own container.
I repeat don't write your own container. Use containers from the standard library. They're well-tested.
While it is possible to cast to void * and back, the problem is knowing which type you're popping. After all, you give the example:
Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());
However, if you were to accidentally do:
Container<int> a = *reinterpret_cast<Container<int>*>(_collection.pop());
Container<string> b = *reinterpret_cast<Container<string>*>(_collection.pop());
Now you've got pointers to the wrong type, and will likely see crashes - or worse.
If you want to do something like this, at least use dynamic_cast to check that you have the right types. With dynamic_cast, you can have C++ check, at runtime (using RTTI), that your cast is safe, as long as the types being casted (both before and after) have a common base type with at least one virtual method.
So, first create a common base type with a virtual destructor:
class ContainerBase {
public:
virtual ~ContainerBase() { }
};
Make your containers derive from it:
template <typename T>
class Container : public ContainerBase {
// ...
}
Now use a std::stack<ContainerBase *>. When you retrieve items from the stack, use dynamic_cast<Container<int> >(stack.pop()) or dynamic_cast<Container<string> >(stack.pop()); if you have the types wrong, these will check, and will return NULL.
That said, heterogeneous containers are almost always the wrong thing to be using; at some level you need to know what's in the container so you can actually use it. What are you actually trying to accomplish by creating a container like this?
I have got two classes.
The first class (A) is builded with an template.
template <class T>
class A
{
public:
T value;
};
The second class (B) should have an object of class A as member variable. Like this:
class B
{
public:
A<int> value;
};
But now i want to use any kind of template-class in class A. Not only int.
Apparent I can't declare a (member-)variable which contains any kind of a class.
So, I need something like this:
class B
{
public:
A<*> value;
};
Is there any (clean) solution for this problem?
-- Greeting from Germany, Bastian
You cannot have a single class B with "any" member object, because B has to be a well-defined class, and A<T> is a different type for different types T. You can either make B a template itself:
template <typename T>
class B
{
A<T> value;
};
or you can take a look at boost::any, which is type-erasing container for arbitrary types (but making use of it requires a certain amount of extra work). The any class only works for value types, though, it's not completely arbitrary.
The simplest solution would be to make all A variants ineherit from a common interface, even if it's empty :
class IA{}
template <class T>
class A : public IA
{
public:
T value;
};
class B
{
public:
IA* value;
};
Now, the associated costs:
interactions with value are limited to the IA interface;
if you try to cast to get the real type, that mean that you know the real type, so it's of no use and make A type a parameter of B becomes really easier to use.
there are runtime costs associated to runtime inheritance
Advantage :
it's easily understood by other developers
it naturally limit the types possible to some specific ones
it don't use boost (sometimes, you just can't)
So to do better there are other less simple solutions but that are simple enough to be used :
If you can use boost, boost::any, boost::variant and boost::mpl might be base of solutions.
Boost any can be used as a safe replacement to void*. The only problem with this is that you can have ANY type, like if the type was a template parameter of the B class.
Boost variant might be used successfully if you know all the types that A can be.
MPL might be helpful if you just want to set a list of possible types and make sure your members apply only to them. You can do a ton of things with MPL so it really depends on your exact needs.
You've got two choices, I think. The first is to parameterize your class over the type parameters of the instance variables:
template <class T> struct B
{
A<T> value;
};
The other option is to declare value as a void* pointer. (But that's probably not what you want).
yes, it's already been done. boost::any.
I think it helps to understand, that templated classes create an entirely new and seperate class for every type you use with it. For instance, Vector<int> and Vector<float> are as separate as the classes VectorInt and VectorFloat.
For class B, you are basically asking that the value variable either be A<int> or A<float>, which is the same as saying you want value to either be a "A_int" or "A_float". And to accomplish that you... well, use another template!