Возможно, вы захотите взглянуть на Loki TypeLists, если вам действительно необходимо отслеживать происхождение и перечислять типы. Я не уверен, что то, о чем ты просишь, действительно возможно без кучки работы. Удостоверьтесь, что вы не перегружены здесь.
На немного другой ноте, если вы собираетесь использовать MI таким образом (т. Е. страшный бриллиант ), тогда вы должны четко указать, какой виртуальный член вам нужен. Я не могу вспомнить хорошего случая, когда вы хотите выбрать семантику B::fn()
вместо C::fn()
без явного принятия решения при написании D
. Вы, вероятно, выберете одно над другим (или даже оба) в зависимости от того, что делает отдельный метод. После того как вы приняли решение, требуется, чтобы унаследованные изменения не изменили ожидания или семантический интерфейс.
Если вы действительно беспокоитесь о замене в новом классе, скажем E
вместо B
, где E
не происходит от B
, но предлагает тот же интерфейс, тогда вам действительно следует использовать шаблон подход, хотя я не уверен, почему там есть static_cast<>
...
struct A {
virtual ~A() {}
virtual void f() = 0;
};
struct B: A {
virtual void f() { std::cout << "B::f()" << std::endl; }
};
struct C: A {
virtual void f() { std::cout << "C::f()" << std::endl; }
};
template <typename Base1, typename Base2>
struct D: Base1, Base2 {
void g() { Base1::f(); Base2::f(); }
};
int main() {
D<B,C> d1;
D<C,B> d2;
d1.g();
d2.g();
return 0;
}
// Outputs:
// B::f()
// C::f()
// C::f()
// B::f()
отлично работает и выглядит немного проще.