I've been playing around with templates lately and I ran into a problem. Lets say I wanted a Container to hold any type, like boost::any. One way to do this would be like that:
/* Abstract base class for my container */
class CAnyBase
{
public:
virtual void* get()=0;
virtual const type_info& type()=0;
};
/* Template class to hold the object */
template<typename TType>
class CAnyType : public CAnyBase
{
public:
CAnyType(TType _object){ object = _object;}
~CAnyType(){}
virtual void* get() { return &object; }
virtual const type_info& type() { return typeid(TType); }
private:
TType object;
};
/* Wrapper class */
class CAnyTypeWrapper
{
public:
template<typename TType> CAnyTypeWrapper(TType _object){ object = new CAnyType<TType>(_object);}
~CAnyTypeWrapper(){}
template<typename TType> bool put(TType& temp) { if(typeid(TType)==object->type()) { temp = *((TType*)object->get()); return 1;} return 0; }
private:
CAnyBase* object;
};
Now this works pretty nicely. You can do things like:
string str = "hi";
vector<CAnyTypeWrapper*> anyvector;
anyvector.push_back(new CAnyTypeWrapper(str)); //StdStrings
anyvector.push_back(new CAnyTypeWrapper(1)); //Integers
anyvector.push_back(new CAnyTypeWrapper('c')); //Chars etc.
However, if I wanted to overload the stream operators to work with my CAnyTypeWrapper for example, the only way I can come up with is this:
friend istream& operator >>(istream &is,CAnyTypeWrapper &obj)
{
if(typeid(int) == obj.object->type()) { is >> *((int*)obj.object->get()); }
else if(typeid(float) == obj.object->type()) { is >> *((float*)obj.object->get()); }
else if(typeid(double) == obj.object->type()) { is >> *((double*)obj.object->get()); }
else if(typeid(char) == obj.object->type()) { is >> *((char*)obj.object->get()); }
else if(typeid(bool) == obj.object->type()) { is >> *((bool*)obj.object->get()); }
else if(typeid(int*) == obj.object->type()) { is >> *((int*)obj.object->get()); }
else if(typeid(float*) == obj.object->type()) { is >> *((float*)obj.object->get()); }
else if(typeid(double*) == obj.object->type()) { is >> *((double*)obj.object->get()); }
else if(typeid(char*) == obj.object->type()) { is >> *((char*)obj.object->get()); }
else if(typeid(bool*) == obj.object->type()) { is >> *((bool*)obj.object->get()); }
else if(typeid(string) == obj.object->type()) { is >> *((string*)obj.object->get()); }
//And so on...
return is;
}
friend ostream& operator <<(ostream &os,const CAnyTypeWrapper &obj)
{
if(typeid(int) == obj.object->type()) { os << *((int*)obj.object->get()); }
else if(typeid(float) == obj.object->type()) { os << *((float*)obj.object->get()); }
else if(typeid(double) == obj.object->type()) { os << *((double*)obj.object->get()); }
else if(typeid(char) == obj.object->type()) { os << *((char*)obj.object->get()); }
else if(typeid(bool) == obj.object->type()) { os << *((bool*)obj.object->get()); }
else if(typeid(int*) == obj.object->type()) { os << *((int*)obj.object->get()); }
else if(typeid(float*) == obj.object->type()) { os << *((float*)obj.object->get()); }
else if(typeid(double*) == obj.object->type()) { os << *((double*)obj.object->get()); }
else if(typeid(char*) == obj.object->type()) { os << *((char*)obj.object->get()); }
else if(typeid(bool*) == obj.object->type()) { os << *((bool*)obj.object->get()); }
else if(typeid(string) == obj.object->type()) { os << *((string*)obj.object->get()); }
//And so on...
return os;
}
Which, of course, isn't very nice. Is there a better way to do this?