Я пытаюсь реализовать полиморфизм во время компиляции, используя CRTP, и хочу заставить производный класс реализовать функцию.
Текущая реализация такова.
template <class Derived>
struct base {
void f() {
static_cast<Derived*>(this)->f();
}
};
struct derived : base<derived>
{
void f() {
...
}
};
В этой реализации вызов функции попадает в бесконечный цикл, если производный класс не реализует f()
,
Как заставить производный класс реализовать функцию, подобную чисто виртуальной функции? Я пытался использовать «static_assert», как static_assert(&base::f != &Derived::f, "...")
но он генерирует сообщение об ошибке, в котором говорится, что два указателя на функцию-член, указывающие на функции-члены разных классов, несопоставимы.
Вы можете присвоить перезаписываемой вещи разные имена, например:
template <class Derived>
struct base {
void f() {
static_cast<Derived*>(this)->fimpl();
}
void fimpl() = delete;
};
struct derived : base<derived> {
void fimpl() { printf("hello world\n"); }
};
Вот, fimpl = delete
в базе, так что он не может быть вызван случайно, если fimpl
переопределяется в производном классе.
Вы также можете вставить промежуточный скрывающий слой в свой CRTP, чтобы «временно» пометить f
как delete
:
template <class Derived>
struct base {
void f() {
static_cast<Derived*>(this)->f();
}
};
template <class Derived>
struct intermediate : base<Derived> {
void f() = delete;
};
struct derived : intermediate<derived> {
void f() { printf("hello world\n"); }
};
template<typename Derived>
class Base
{
private:
static void verify(void (Derived::*)()) {}
public:
void f()
{
verify(&Derived::f);
static_cast<Derived*>(this)->f();
}
};
Если производный класс не реализует f
сам по себе, тип &Derived::f
было бы void (Base::*)()
, который нарушает компиляцию.
Начиная с C ++ 11 мы также можем сделать эту функцию обобщенной с помощью шаблона с переменными числами.
template<typename Derived>
class Base
{
private:
template<typename T, typename...Args>
static void verify(T (Derived::*)(Args...)) {}
};