По практическим соображениям у меня есть такой класс
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)
?
Вы можете устранить неоднозначность, указав имя базового шаблона. Следующее должно работать:
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>();
}
};
Я обнародовал все, чтобы не увязнуть в деталях контроля доступа.
Других решений пока нет …