Статический полиморфизм: как определить интерфейс?

Ниже приведен очень простой пример того, что я понимаю как статический полиморфизм. Причина, по которой я не использую динамический полиморфизм, состоит в том, что я не хочу препятствовать встраиванию функций PROCESSOR в op,

template <class PROCESSOR>
void op(PROCESSOR* proc){
    proc->doSomething(5);
    proc->doSomethingElse();
}

int main() {
    ProcessorY py;
    op<ProcessorY>(&py);
    return 0;
}

Проблема с этим примером заключается в следующем: не существует явного определения того, какие функции PROCESSOR должен определить. Если один из них отсутствует, вы просто получите ошибку компиляции. Я думаю, что это плохой стиль.

Он также имеет очень практический недостаток: он-лайн поддержка IDE, конечно, не может показать вам функции, доступные для этого объекта.

Что такое хороший / официальный способ определения публичного интерфейса PROCESSOR?

2 ответа

Решение

Во-первых, я думаю, что нет проблем с вашим примером статического полиморфизма. Поскольку он статичен, то есть разрешен во время компиляции, он по определению предъявляет менее строгие требования к определению интерфейса.

Также абсолютно законно, что неправильный код просто не будет компилироваться / ссылаться, хотя более понятное сообщение об ошибке от компилятора будет лучше.

Однако если вы настаиваете на определении интерфейса, вы можете переписать свой пример следующим образом:

template <class Type>
class Processor
{
public:
    void doSomething(int);
    void doSomethingElse();
};

template <class Type>
void op(Processor<Type>* proc){
    proc->doSomething(5);
    proc->doSomethingElse();
}

// specialization
template <>
class Processor<Type_Y>
{
    // implement the specialized methods
};

typedef Processor<Type_Y> ProcessorY;

int main() {
    ProcessorY py;
    op(&py);
    return 0;
}

Не существует четкого определения того, какие методы должен определять ПРОЦЕССОР. Если один из них отсутствует, вы просто получите ошибку компиляции. Я думаю, это плохой стиль.

Это. Это не. Это может быть. Это зависит.

Да, если вы хотите определить поведение таким образом, вы можете также ограничить содержимое, которое должны иметь параметры шаблона. К сожалению, это невозможно сделать прямо сейчас.

То, что вам нужно, это функция ограничений и концепций, которая должна была появиться как часть C++ 11, но была отложена и по-прежнему недоступна в C++ 14.

Однако получение ошибки во время компиляции часто является лучшим способом ограничения параметров шаблона. В качестве примера мы можем использовать std библиотека:

1) Итераторы.

Библиотека C++ определяет несколько типов итераторов: forward_iterator, random_access_iterator и другие. Для каждого типа определен набор свойств и допустимых выражений, которые гарантированно будут доступны. Если вы использовали итератор, это не полностью совместимо с random_access_iterator в контейнере, который требует random_access_iterator, вы получите ошибку компилятора в некоторый момент (скорее всего, при использовании оператора разыменования ([]), который требуется в этом классе итераторов).

2) Распределители.

Все контейнеры в std библиотека использует распределитель для выполнения выделения / освобождения памяти и построения объектов. По умолчанию используется std::allocator. Если вы хотите обменять его на свой, вы должны убедиться, что он имеет все, что std::allocator гарантированно иметь. В противном случае вы получите ошибку во время компиляции.

Итак, пока мы не получим концепции, это лучшее и наиболее широко используемое решение.

Другие вопросы по тегам