Я пытаюсь создать универсальный контейнер, который может хранить гетерогенные объекты типа Wrapper< T> где T может быть любым определяемым пользователем типом. Я видел boost :: any и другие решения, но я не могу вызвать функцию foo () без перезаписи (я не знаю, какой тип перезаписать, информация о T теряется). Она возвращается к исходному типу.
Как я могу разумно реализовать универсальный контейнер / использовать существующий универсальный контейнер для достижения этой цели?
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;
}
}
Наиболее общий способ — создать базовый класс для Wrapper, скажем, BaseWrapper, и определить чисто виртуальные функции BaseWrapper, которые затем будут реализованы в каждом из классов Wrapper. Благодаря специализации каждый Wrapper, Wrapper, может иметь свою собственную реализацию. Сделав это, вы можете использовать контейнер с умным указателем на базовый тип и использовать его на досуге.
Есть несколько возможных ярлыков. Например, в простом случае в вашем примере, я бы рекомендовал использовать std::function
, В этом помогает вспомогательная функция. Обратите внимание, что это действительно работает, только если вызывается только 1 метод. Я бы также порекомендовал определить вашу обертку operator()
напрямую, чтобы вам не пришлось использовать привязку.
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;
}
}
Редактировать:
То, что я обсуждал, было не шаблонной основой, из которой вы извлекаете все свои шаблонные обертки. Это позволяет вам вызывать методы, которые вы предварительно определили (и которые должны быть реализованы оболочкой), не зная конкретного типа оболочки.
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;
}
}
Других решений пока нет …