Выбор базового класса CRTP для наследования

Допустим, у меня есть следующий очень простой базовый класс CRTP:

template< class D, class T >
struct Base
{

    T foo() 
    {   
        return static_cast< D* >(this)->foo_i();
    }

};

А также, несколько производных классов. Все работает хорошо, но есть проблема: есть одна конкретная ситуация (или, может быть, пара), где мне бы очень хотелось , чтобы два класса имели полиморфное поведение во время выполнения (нужно поместить их в контейнеры). Другими словами, я бы хотел, чтобы некоторые производные классы CRTP также имели виртуальные версии. Итак, я придумал следующий класс:

template< class T >
struct VirtualBase : public Base< VirtualBase< T >, T >
{

    virtual T foo_i() = 0;

};

Теперь, когда мне нужен полиморфизм времени выполнения, я просто наследую этот класс. Допустим, я хочу свой производный класс DerivedB иметь виртуальную версию. Ванильный DerivedB выглядит так:

template< class T >
struct DerivedB : public Base< DerivedB< T >, T >
{

    T foo_i() 
    { 
        std::cout << "I'm special!\n";
        return T(); 
    }

};

По сути, я хотел бы добавить дополнительный параметр шаблона к этому классу, чтобы я мог во время компиляции выбрать, наследовать ли я от Base (если я хочу смоделированное "динамическое" связывание) или VirtualBase (если я хочу реальное динамическое связывание)). Что-то вроде следующего псевдо-C++:

template< class B, class T >
struct DerivedB : public B< DerivedB< T >, T >
{

    T foo_i() 
    { 
        std::cout << "I'm special!\n";
        return T(); 
    }

};

Так что для простого CRTP, пройти Base как B и для виртуального класса, пройти VirtualBase как B, Проблема, конечно, в том, что они принимают разное количество аргументов (Base нужен тип производного класса), и я не могу найти рабочее решение.

Итак, как бы я выбрал базовый класс во время компиляции? Или, если это слишком сложно / невозможно, каков будет самый простой способ иметь статические (CRTP) и динамические (виртуальные) версии класса, где в противном случае реализация идентична?

1 ответ

Решение

Возможно, самый простой способ - просто добавить "класс D" в качестве неиспользуемого параметра шаблона VirtualBase, чтобы он соответствовал тому же интерфейсу.

Если вы не можете изменить VirtualBase, вы можете использовать промежуточный шаблон:

template <class D, class T> class VirtualBaseWrapper : public VirtualBase<T>{}
Другие вопросы по тегам