Для меня в шаблоне C ++ использовалась идея «утиной печати», верно? Означает ли это, что все общие типы, указанные в классе или методе шаблона, относятся к типу утки?
Какая связь между шаблоном C ++ и утиным набором текста?
Ответы (7)
Для меня в шаблоне C ++ использовалась идея «утиной печати», верно?
Нет, шаблоны C ++ используются для реализации универсального кода. То есть, если у вас есть код, который может работать с более чем одним типом, вам не нужно дублировать его для каждого типа. Такие вещи, как std::vector
и std::list
- очевидные примеры этого в действии. Шаблоны C ++ использовались для выполнения других задач, но изначальной целью была универсальность.
Означает ли это, что все общие типы, указанные в классе или методе шаблона, относятся к типу утки?
Нет, это просто «нормальные» типы, как и любой другой тип в C ++. Они просто не известны, пока шаблон не будет фактически создан.
Однако шаблоны можно использовать для реализации чего-то вроде утиного набора текста. Итераторы являются примером. Рассмотрим эту функцию:
template<class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
OutputIterator result)
{
while (first!=last) *result++ = *first++;
return result;
}
Обратите внимание, что функция copy
может принимать аргументы любого типа, а также реализует оператор неравенства, оператор разыменования и оператор постфиксного приращения. Это, вероятно, так близко к утиной печати, как вы получите в C ++.
Для меня шаблоны C ++ - это версия утиной печати во время компиляции. Компилятор будет компилировать, например, Class, и пока ваш Duck имеет все необходимые типы, он будет создавать экземпляр класса.
Если что-то не так (например, отсутствует конструктор копирования), компиляция не выполняется. Аналогом в реальном ducktyping является сбой, когда вы вызываете функцию с типом, отличным от ducktyping. И вот это произойдет во время выполнения.
Утиная печать означает: «Если она крякает, как утка, и ходит как утка, значит, это утка». В информатике нет формального определения, с которым мы могли бы сравнивать C ++.
Конечно, C ++ не идентичен (например) Python, но оба они имеют концепцию неявно определенных интерфейсов. Интерфейс, требуемый для объекта, используемого в качестве аргумента функции Python, - это то, что функция с ним делает. Интерфейс, требуемый для типа, используемого в качестве аргумента шаблона C ++, соответствует тому, что шаблон делает с объектами этого типа. В этом сходство, и это основание, по которому следует оценивать шаблоны C ++.
Кроме того, из-за вывода аргументов шаблона в C ++ вы можете попытаться передать любой старый объект, и компилятор выяснит, может ли он создать экземпляр шаблона функции.
Одно отличие состоит в том, что в C ++, если аргумент не крякает, компилятор возражает. В Python только объекты времени выполнения (и только если функция действительно вызывается, если в коде есть условные выражения). Это различие в природе интерфейса, требуемого от объекта / типа - в C ++ либо шаблон требует, чтобы конкретное выражение было действительным, либо этого не требует. В Python необходимые допустимые выражения могут зависеть от значений времени выполнения ранее необходимых выражений. Итак, в Python вы можете попросить объект, который либо громко, либо тихо крякает, а если он громко крякает, ему тоже нужно ходить. В C ++ вы можете сделать это с помощью условного dynamic_cast
, и если объем является константой времени компиляции, вы можете сделать это со специализацией шаблона, но вы не можете использовать статическую типизацию, чтобы сказать, что утке нужно ходить только в том случае, если quack_volume()
возвращает loud
. И, конечно же, в Python требуемый интерфейс может быть не совсем «обязательным» - поведение, если метод отсутствует, вызывает исключение, и можно было бы задокументировать и гарантировать поведение вызывающего, если это произойдет.
Вам решать, определяете ли вы «утиную печать», чтобы это различие означало, что в C ++ ее нет.
Не совсем. Утиные типы (стиль динамического типа) никогда не вызовут ошибок типа во время компиляции, потому что они просто не имеют никакого типа. С шаблонами у вас не будет типов, пока вы не создадите экземпляр шаблона. Как только вы это сделаете, переменные будут иметь разные типы, и вы действительно получите ошибки времени компиляции.
Кроме того, с типами утки у вас может быть одна переменная, указывающая на разные типы объектов, потому что переменные просто не имеют типов. Это невозможно с шаблонами - после их создания переменные имеют один определенный тип.
Однако они похожи в том, что ограничения являются неявными: проверяются только фактически используемые функции. В отличие, скажем, от полиморфных указателей фактический тип не имеет значения.
Да, вроде - например, если тип X
имеет методы AddRef()
, Release()
и QueryInterface()
с соответствующими сигнатурами, его можно использовать как объект COM с классом шаблона CComPtr
. Но это не полная утиная типизация - для параметров по-прежнему применяется проверка типов.
Нет, это другое понятие. duck typing - это метод определения типа контейнера с динамической типизацией. Шаблоны C ++ не являются динамически типизированными, они создаются с конкретным типом.