Возможна ли эмуляция чистой виртуальной функции в статическом полиморфизме с использованием CRTP?

Я пытаюсь реализовать полиморфизм во время компиляции, используя 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, "...") но он генерирует сообщение об ошибке, в котором говорится, что два указателя на функцию-член, указывающие на функции-члены разных классов, несопоставимы.

7

Решение

Вы можете присвоить перезаписываемой вещи разные имена, например:

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"); }
};
6

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

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...)) {}
};
2

По вопросам рекламы [email protected]