Если все F<X>
не получены из некоторого общего базового класса, независимого от X
, это возможно только при использовании стирания типов или гетерогенных контейнеров.
Если все они наследуются от Foo
, то изКонечно, вы можете перебирать их как Foo&
/ Foo*
, но я думаю, вы знали, что.
Если они имеют разные типы, стандартные контейнеры не могут их содержать, потому что они однородны - все элементы имеюттого же типа.Вероятно, есть какая-то библиотека с гетерогенными контейнерами, но в STL вы можете эмулировать это только с помощью std::variant
или std::any
.
Последний способ, которым я мог представить, работает - я не рекомендую это- путем создания включающего класса как производного класса F<X>
s (шаблон переменной) и кодирования вызовов в иерархии, каждый F s
foo` называется
, поскольку это несколько большеЗдесь приведен пример:
#include <iostream>
template <class X>
class Foo {
X mem;
public:
explicit Foo(X arg) : mem(arg) {}
void foo() {
std::cout << mem;
}
};
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X> {
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg)) {}
void call() {
member.foo();
}
};
template <class X, class ...Ys>
class Holder : public Holder<Ys...> {
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg)) { }
void call() {
member.foo();
Holder<Ys...>::call();
}
};
int main() {
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
}
Возможно, вы сможете догадаться, что это, как правило, не то, что вам нужно, потому что это очень сложно.На самом деле я пропустил некоторые вещи, такие как идеальная пересылка аргументов, чтобы сделать их несколько минимальными, и можно надеяться, что концепция понятна.