[..] I want to eventually write vector<Arbitrary*> name;
Arbitrary
is a template, not a type. To "obtain" a type from it, you need to "apply" it to another type (like int
). This gives you Arbitrary<int>
as "result" type. This process is called template instantiation.
If you want a vector with objects of any possible type that might have been instantiated from the template Arbitrary
, then you need to give them a common type (such that every object "is a" object of that common type). This is because std::vector
stores only objects of a single type.
To have the objects "behave" (in the sense of having some type) differently even though they "have" a common type, you need to make them (or rather their common type) polymorphic. This is done by giving the common type some virtual
function. (And since you want to delete/destruct objects through the "interface" exposed by the common type you need to make the destructor virtual!)
struct ArbitraryBase {
// Add "common interface" functions here, as virtual
virtual ~ArbitraryBase() = 0; // pure virtual to avoid creating objects
};
inline ArbitraryBase::~ArbitraryBase() {}
template<typename T>
struct Arbitrary : ArbitraryBase {
// whatever
};
Now, to actually be able to use that polymorphic property and not become victim of object slicing you need to use reference or pointer semantics:
std::vector<ArbitraryBase *> objects;
Instead of raw pointers you should consider smart pointers like std::unique_ptr<ArbitraryBase>
if the objects
vector should have ownership of the objects or otherwise use std::reference_wrapper<ArbitraryBase>
in case lifetime of the objects is reliably handled by something else.
But if you don't add any common interface (more virtual member functions) in ArbitraryBase
then you're basically reinventing std::any
/ boost::any
. So better use those well tested implementations instead.