Существует ли реальный статический полиморфизм в C++?
Безусловно — есть три механизма статического полиморфизма: шаблоны, макросы и перегрузка функций.
Итак, как я понял, компилятор С++ разделит одну определенную функцию на различное количество (зависит от количества вызовов с разным типом) функций. Прав я или нет?
Это общая идея. Количество создаваемых функций зависит от количества перестановок параметров шаблона, которые могут быть явно указаны, как в function<int>
и function<double>
, или - для шаблонов, которые используют параметры шаблона для сопоставления аргументов функции - автоматически получены из аргументов функции, например :
template <typename T, size_t N>
void f(T (&array)[N])
{ }
double d[2];
f(d); // instantiates/uses f<double, 2>()
Вы должны получить единственную копию каждого экземпляра шаблона в исполняемом двоичном образе.
Я хочу знать, могу ли я описать приведенный выше код как статический полиморфизм?
Не совсем так.
template<> function
создается для двух типов
что особенно важно, полиморфизм не используется для выбора, какой из двух экземпляров function
отправлять на сайты вызовов.
тривиально, во время таких экземпляров typeid(T)
оценивается для int
и double
и эффективно ведет себя полиморфно с точки зрения программиста (хотя это ключевое слово компилятора - реализация неизвестна)
тривиально, сочетание статического и номинально динамического (но здесь, вероятно, оптимизируемого до статического) полиморфизма поддерживает ваше использование std::cout
Предыстория — полиморфизм и генерация кода
Требование, которое я считаю решающим для полиморфизма:
когда код компилируется (будь то "обычный" код, создание экземпляра шаблона или подстановка макроса), компилятор автоматически выбирает (создает, если необходимо) - и либо встраивает, либо вызывает - определенное поведение, соответствующее типу (машинный код )
т. е. выбор/создание кода выполняется компилятором на основе только типа (типов) задействованных переменных (переменных), а не явно жестко запрограммированного выбором программиста между различными именами функций / экземплярами, каждый из которых способен обрабатывать только один тип или перестановка типов
например, std::cout << x;
полиморфно вызывает другой код, так как тип x
варьируется, но по-прежнему выводит значение x
, в то время как неполиморфный printf("%d", x)
обрабатывает int
, но его необходимо вручную изменить на printf("%c", x);
, если x
становится char
.
Но то, чего мы пытаемся достичь с помощью полиморфизма, носит более общий характер:
повторное использование алгоритмического кода для нескольких типов данных без встраивания явного кода определения типа и ветвления
- that is, without the program source code containing
if (type == X) f1(x) else f2(x);
-style code
уменьшение затрат на обслуживание, так как после явного изменения типа переменной требуется меньше последовательных изменений, которые необходимо вносить вручную в исходный код.
Эти общие аспекты поддерживаются в C++ следующим образом:
создание экземпляра одного и того же исходного кода для создания отличных вариантов поведения strong> (машинный код) для некоторого другого типа или перестановки типов (это аспект параметрического em> полиморфизм),
- actually known as "instantiation" for templates and "substitution" for preprocessor macros, but I'll use "instantiation" hereafter for convenience; conceptually, re-compilation or re-interpretation...
неявная отправка (статическая или динамическая) в определенное поведение (машинный код), соответствующее различные типы обрабатываемых данных.
... и в некоторых второстепенных отношениях согласно моему ответу на Полиморфизм в c++
Различные типы полиморфизма включают один или оба из них:
отправка (2) может происходить во время создания экземпляра (1) для шаблонов и макросов препроцессора,
создание экземпляра (1) обычно происходит во время отправки (2) для шаблонов (без соответствующей полной специализации) и функциональных макросов< /strong> (типа циклического, хотя макросы не расширяются рекурсивно)
отправка (2) может происходить без создания экземпляра (1) когда компилятор выбирает уже существующую функцию < strong>перегрузка или специализация шаблона, или когда компилятор запускает виртуальную/динамическую диспетчеризацию.
Что на самом деле использует ваш код?
function<int>
и function<double>
повторно используют код шаблона function
для создания отдельного кода для каждого из этих типов, поэтому вы получаете экземпляр (1), как указано выше. Но вы жестко кодируете, какой экземпляр вызывать, вместо того, чтобы компилятор неявно выбирал экземпляр на основе типа некоторого параметра, т. е. вы не напрямую используете неявную отправку ala (2), когда звоню function
. Действительно, в function
отсутствует параметр, который компилятор мог бы использовать для неявного выбора экземпляра шаблона.
Одного экземпляра (1) недостаточно, чтобы считать, что в вашем коде используется полиморфизм. Тем не менее, вы добились удобного повторного использования кода.
Так что же было бы однозначно полиморфным?
Чтобы проиллюстрировать, как шаблоны могут поддерживать диспетчеризацию (2), а также создание экземпляров (1) и бесспорно обеспечивать "полиморфизм", рассмотрим:
template<typename T>
void function(T t)
{
std::cout << typeid(T).name() << std::endl;
}
function(4); // note: int argument, use function<int>(...)
function(12.3); // note: double argument, use function<double>(...)
В приведенном выше коде также используется неявная отправка кода, соответствующего типу — аспект "2". выше - полиморфизма.
Нетиповые параметры
Интересно, что C++ предоставляет возможность создавать экземпляры шаблонов с целыми параметрами, такими как логические значения, int
и константы-указатели, и использовать их для самых разных целей без изменения типов данных и, следовательно, без участия полиморфизма. Макросы еще более гибкие.
Обратите внимание, что использование шаблона в C.R.T.P. стиль НЕ является требованием статического полиморфизма — это пример его применения. Во время создания экземпляра компилятор демонстрирует статический полиморфизм при сопоставлении операций с реализациями в типе, указанном параметром.
Обсуждение терминологии
Получить окончательное определение полиморфизма сложно. Википедия цитирует онлайн-глоссарий Бьярна Страуструпа «предоставление единого интерфейса для объектов разных типов»: это подразумевает, что struct X { void f(); }; struct Y { void f(); };
уже проявляет полиморфизм, но ИМХО мы получаем полиморфизм только тогда, когда мы используем соответствие интерфейса из клиентского кода, например. template <typename T> void poly(T& t) { t.f(); }
требует статической полиморфной отправки в t.f()
для каждого экземпляра.
person
Community
schedule
26.12.2013