Reputation: 43
I am trying to create a generic container which can store heterogeneous objects of type Wrapper< T> where T can be any user defined type. I have seen boost::any and other solutions, but i cant call the function foo() without recasting(i dont know which type to recast,information about T is lost.) it back to original type.
How can I reasonably implement a Generic container/use existing generic container to achieve this ?
template <typename T>
class Wrapper{
public:
Wrapper(const T& a):o(a){};
Wrapper(){};
//public methods
void foo(){
//do stuff
};
private:
T o;
};
class X{};
class Y{};
int main(){
X x;
Y y;
A_GENERIC_CONTAINER generic_container;
// A_GENERIC_CONTAINER should be able to store
// any number of heterogeneous objects of type Wrapper<T>
// where T can be any user defined type.
generic_container.push_back(x);
generic_container.push_back(y);
auto it = generic_container.begin();
auto end = generic_container.end();
while(it != end){
it->foo();
++it;
}
}
Upvotes: 3
Views: 3762
Reputation: 21058
The most generic way is to create a base class for Wrapper, say BaseWrapper, and define the pure virtual functions on the BaseWrapper that then are implemented on each of the Wrapper classes. Through specialization, each Wrapper, Wrapper, could have their own implementation. Once you've done that, you can use a container of a smart pointer to the Base Type, and use it at your leisure.
There are some possible shortcuts. For example, in the simple case in your example, I would recommend using std::function
. A helper function aids in doing this. Note, this really only works if there is only 1 method to be called. I also would recommend having your wrapper define operator()
directly, so that you don't have to use the bind.
template<T>
std::function<void()> wrap(const T& x)
{
return std::bind(&Wrapper<T>::foo, Wrapper<T>(x));
}
int main(){
X x;
Y y;
std::vector<std::function<void()> > generic_container;
// A_GENERIC_CONTAINER should be able to store
// any number of heterogeneous objects of type Wrapper<T>
// where T can be any user defined type.
generic_container.push_back(wrap(x));
generic_container.push_back(wrap(y));
auto it = generic_container.begin();
auto end = generic_container.end();
while(it != end){
(*it)();
++it;
}
}
Edit:
What I was discussing was a non-templated base, from which you derive all of your templated wrappers. This allows you to call the methods you have pre-defined (and that must be implemented by the Wrapper), without knowing the specific wrapper type involved.
class Base
{
public:
virtual ~Base() {};
virtual void foo() = 0;
};
template <typename T>
class Wrapper : public Base{
public:
Wrapper(const T& a):o(a){};
Wrapper(){};
//public methods
virtual void foo(){
//do stuff
};
private:
T o;
};
int main(){
X x;
Y y;
std::vector<std::shared_ptr<Base> > generic_container;
// A_GENERIC_CONTAINER should be able to store
// any number of heterogeneous objects of type Wrapper<T>
// where T can be any user defined type.
generic_container.push_back(std::make_shared<Wrapper<X>>(x));
generic_container.push_back(std::make_shared<Wrapper<Y>>(y));
auto it = generic_container.begin();
auto end = generic_container.end();
while(it != end){
it->foo();
++it;
}
}
Upvotes: 5