допустим есть у нас набор шаблонных классов, которые наследуют от своего параметра
из них я хочу сгенерировать класс, имеющий сложную иерархическую структуру
вроде все хорошо. но проблема вот в чем. у меня в дереве MyStruct имеется два различных класса A, которые все же имеют функцию foo с одинаковой сигнатурой. поэтому я не могу просто вызвать my_struct.foo() из-за возникающей неоднозначности.
меня интересует, есть ли какие-нибудь известные методы для того, что бы как-нибудь помечать конкретные классы в иерархии и потом получать к ним доступ? естесственно интересует только compile-time, в run-time все далется тривиально через dynamic_cast
а мне бы хотелось как-нибудь вот так tag_cast<first_A_class_tag>(my_struct).foo(); tag_cast<second_A_class_tag>(my_struct).foo();
что-то пока никакое решение в голову не приходит
Здравствуйте, CyberZX, Вы писали:
CZX>допустим есть у нас набор шаблонных классов, которые наследуют от своего параметра
CZX>
CZX>из них я хочу сгенерировать класс, имеющий сложную иерархическую структуру
CZX>
CZX>вроде все хорошо. но проблема вот в чем. у меня в дереве MyStruct имеется два различных класса A, которые все же имеют функцию foo с одинаковой сигнатурой. поэтому я не могу просто вызвать my_struct.foo() из-за возникающей неоднозначности.
CZX>меня интересует, есть ли какие-нибудь известные методы для того, что бы как-нибудь помечать конкретные классы в иерархии и потом получать к ним доступ? естесственно интересует только compile-time, в run-time все далется тривиально через dynamic_cast
CZX>а мне бы хотелось как-нибудь вот так tag_cast<first_A_class_tag>(my_struct).foo(); tag_cast<second_A_class_tag>(my_struct).foo();
CZX>что-то пока никакое решение в голову не приходит
Может так?
struct E {};
template <typename T>
struct A: public T
{
void foo() { cout << "A<T>::foo()\n"; }
};
// специализация просто, чтобы показать вызов foo из A<E>
template <>
void A<E>::foo() { cout << "A<E>::foo()\n"; }
template <typename T>
struct B: public T {};
template <typename T, typename U>
struct C: public T, public U {};
struct M: public A<C<B<E>, A<E> > >
{
void foo1() { A<C<B<E>, A<E> > >::foo(); }
void foo2() { A<E>::foo(); }
};
int main()
{
M m;
m.foo1();
m.foo2();
return 0;
}
The last good thing written in C was Franz Schubert's Symphony No. 9.
Здравствуйте, CyberZX, Вы писали:
CZX>вроде все хорошо. но проблема вот в чем. у меня в дереве MyStruct имеется два различных класса A, которые все же имеют функцию foo с одинаковой сигнатурой. поэтому я не могу просто вызвать my_struct.foo() из-за возникающей неоднозначности.
CZX>меня интересует, есть ли какие-нибудь известные методы для того, что бы как-нибудь помечать конкретные классы в иерархии и потом получать к ним доступ? естесственно интересует только compile-time, в run-time все далется тривиально через dynamic_cast
CZX>а мне бы хотелось как-нибудь вот так tag_cast<first_A_class_tag>(my_struct).foo(); tag_cast<second_A_class_tag>(my_struct).foo();
CZX>что-то пока никакое решение в голову не приходит
Неоднозначность можно разрешить явно указав "путь" к функции:
my_struct.A::B::Binary::D::A::foo();
Или использовать виртуальное наследование чтобы в my_struct была одна копия класса А.
Вроде так.
Здравствуйте, CyberZX, Вы писали:
А может быть лучше вместо параметризации классов предком параметризовать их наследником (CRTP как в ATL)?
#define DECLARE_DERIVED_AS_SELF \
Derived const & self() const { return static_cast<Derived const &>(*this); } \
Derived & self() const { return static_cast<Derived &>(*this); }
template <class Derived> struct A
{
void do_something();
A & a() { return *this; }
private:
DECLARE_DERIVED_AS_SELF
};
template <class Derived> struct B
{
void do_something();
B & b() { return *this; }
private:
DECLARE_DERIVED_AS_SELF
};
template <class Derived> struct C
{
void somefunc()
{
self().a().do_something();
self().b().do_something();
}
C & c() { return *this; }
private:
DECLARE_DERIVED_AS_SELF
};
Список базовых классов задавать mpl::vector'ом унарных метафункций (точнее: лямбда выражений):
namespace mpl = boost::mpl;
typedef mpl::placeholders::_ __;
struct bases : mpl::vector<A<__>, B<__>, C<__> > {};
И генерировать сам класс таким образом:
template <class Base, class Node, class Derived>
struct inherit_and_apply_on_derived : Base, mpl::apply<Node, Derived>::type
{
};
struct D : mpl::inherit_linearly<bases, inherit_and_apply_on_derived<__, __, D> >::type
{};
Вполне жизнеспособный дизайн...