Наследование и CRTP

По практическим соображениям у меня есть такой класс

template <class A>
class CRTP
{
template <int (A::*Member)()>
int func(void * obj)
{
int result
// Do something with Member, like
// result = (reinterpret_cast<A*>(obj)->*Member)();
return result;
}
};

template <void (A::*Member)()> это требование, оно не может быть передано в качестве аргумента.

И у меня тоже есть класс Base

class Base : public CRTP<Base>
{
int aMemberOfBase() {...}
};

И его производный, который я хочу также наследовать CRTP

class Derived : public CRTP<Derived>, public Base
{
int aMemberOfDerived() {...}
};

В каком-то члене Derived я сделаю что-то вроде

func<&Derived::aMemberOfDerived>(this);
func<&Base::aMemberOfBase>(this);

Это возможно ?

(Ну, VC ++ компилирует только первую строку и не хочет читать о второй … но в Derived должны быть члены

template <int (Base::*Member)()> int func(void * obj);
template <int (Derived::*Member)()> int func(void * obj);

что выглядит странно, я признаю это. Но следующий кусок кода

template <void (Base::*Member)()> int func() {return 0;}
template <void (Derived::*Member)()> int func() {return 1;}

компилирует и возвращает func<&Base::someMember>() != func<&Derived::someMember>()потому что подпись шаблона не совпадает и не может быть одинаковой.)

Я должен признать, что я не очень хорошо понимаю то, что говорит стандарт. Но разрешен ли образец наследования, который я пытаюсь разрешить? И если да, то почему одна строка не компилируется?

Более того, если я заявляю

class Derived : public Base, public CRTP<Derived>

вместо

class Derived : public CRTP<Derived>, public Base

Я получаю ошибку времени компиляции (на всех func<...>(...)), что означает, что где-то что-то не так.

С другой стороны, я знаю, что

template <class A, int (A::*Member)()> int func(void * obj)

убрал бы необходимость в CRTP, но писать было бы больно func<Derived, &Derived::aMember>(), Есть ли обходной путь, как

template <class Class, void (Class::*Member)()> class A
{
void func(void * obj) {...(reinterpret_cast<Class*>(obj)->*Member)();...}
};
template <typename Signature> class B;

template <typename Class, typename Member>
class B<&Class::Member> : public class A<Class, &Class::Member> {};

что позволило бы B<&Base::Derived>().func(somePtrToBase)?

1

Решение

Вы можете устранить неоднозначность, указав имя базового шаблона. Следующее должно работать:

template <typename A> struct CRTP
{
template <int (A::*Member)()> int func();
};

struct Base : CRTP<Base>
{
int aMemberOfBase();
};

struct Derived : CRTP<Derived>, Base
{
int aMemberOfDerived();

void foo()
{
CRTP<Derived>::func<&Derived::aMemberOfDerived>();
CRTP<Base>::func<&Base::aMemberOfBase>();
}
};

Я обнародовал все, чтобы не увязнуть в деталях контроля доступа.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector