Jump to content
  • Advertisement
Sign in to follow this  
kloffy

[C++] Container for any type

This topic is 4520 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
Advertisement
/* Abstract base class for my container */
class CAnyBase
{
public:
virtual void* get()=0;
virtual const type_info& type()=0;
virtual std::istream & read(std::istream &)=0;
virtual std::ostream & write(std::ostream &)=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); }
virtual std::istream & read(std::istream & reader) { return reader >> object; }
virtual std::ostream & write(std::ostream & writer) { return writer << object; }
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; }

friend std::istream & operator>>(std::istream & reader, CAnyTypeWrapper & obj) { return obj.object->read(reader); }

friend std::ostream & operator<<(std::ostream & writer, CAnyTypeWrapper & obj) { return obj.object->write(writer); }

private:
CAnyBase* object;
};

I prefer boost::any to your solution.

Σnigma

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Make stream operators for CAnyBase and just call "is >> obj.object;" in the function you have now. CAnyBase's stream operator should call a new virtual function "getFromStream" declared at CAnyBase and defined at CAnyType. In CAnyType the getFromStream function simply calls is >> object; Here the type of object is known and it calls directly the correct >>-operator.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Aww, I was slow.

Share this post


Link to post
Share on other sites
@RDragon1:
Actually I'm not really interested in the container. What I really want is a functor class that can hold different types of functions. I ran into the same problem though - and the container is the easier example.

@Enigma:
As far as I can tell boost::any isn't really that different. Why do you think it's better?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by kloffy
@Enigma:
As far as I can tell boost::any isn't really that different. Why do you think it's better?
At least it's semi-standard so if everyone uses boost::any instead of custom solutions, people don't have to relearn the same feature every time.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Make stream operators for CAnyBase and just call "is >> obj.object;" in the function you have now. CAnyBase's stream operator should call a new virtual function "getFromStream" declared at CAnyBase and defined at CAnyType. In CAnyType the getFromStream function simply calls is >> object; Here the type of object is known and it calls directly the correct >>-operator.

That sounds good, I'll try it...

Btw.: I doubt anybody will have to relearn the same feature, because I'm not planning to release this. It's just for learning purposes on my behalf...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by kloffy
That sounds good, I'll try it...
It's roughly the same as what Enigma gave in code. Only he calls the virtual function directly from CAnyTypeWrapper's stream operator..

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
It's roughly the same as what Enigma gave in code. Only he calls the virtual function directly from CAnyTypeWrapper's stream operator..

Oh, I missed that. I thought he only quoted the code to say he prefers boost::any. Thanks both of you for your help!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!