~~~~~~~~~~~~~~~~~~~~ Arc.Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~ 
Номер скриншота №:
✰ F0EC3E9BDC90DC5730B2CCCC6E1BA089__1714276080 ✰
Заголовок документа оригинал.:
✰ Generic programming - Wikipedia ✰
Заголовок документа перевод.:
✰ Общее программирование — Википедия ✰
Снимок документа находящегося по адресу (URL):
✰ https://en.wikipedia.org/wiki/Generic_programming ✰
Адрес хранения снимка оригинал (URL):
✰ https://arc.ask3.ru/arc/aa/f0/89/f0ec3e9bdc90dc5730b2cccc6e1ba089.html ✰
Адрес хранения снимка перевод (URL):
✰ https://arc.ask3.ru/arc/aa/f0/89/f0ec3e9bdc90dc5730b2cccc6e1ba089__translat.html ✰
Дата и время сохранения документа:
✰ 11.06.2024 05:53:57 (GMT+3, MSK) ✰
Дата и время изменения документа (по данным источника):
✰ 28 April 2024, at 06:48 (UTC). ✰ 

~~~~~~~~~~~~~~~~~~~~~~ Ask3.Ru ~~~~~~~~~~~~~~~~~~~~~~ 
Сервисы Ask3.ru: 
 Архив документов (Снимки документов, в формате HTML, PDF, PNG - подписанные ЭЦП, доказывающие существование документа в момент подписи. Перевод сохраненных документов на русский язык.)https://arc.ask3.ruОтветы на вопросы (Сервис ответов на вопросы, в основном, научной направленности)https://ask3.ru/answer2questionТоварный сопоставитель (Сервис сравнения и выбора товаров) ✰✰
✰ https://ask3.ru/product2collationПартнерыhttps://comrades.ask3.ru


Совет. Чтобы искать на странице, нажмите Ctrl+F или ⌘-F (для MacOS) и введите запрос в поле поиска.
Arc.Ask3.ru: далее начало оригинального документа

Общее программирование — Википедия Jump to content

Общее программирование

Из Википедии, бесплатной энциклопедии

Универсальное программирование — это стиль компьютерного программирования , в котором алгоритмы записываются с использованием типов данных, которые должны быть указаны позже, а затем при необходимости создаются экземпляры для конкретных типов, представленных в качестве параметров . Этот подход, впервые использованный в языке программирования ML в 1973 году, [1] [2] позволяет писать общие функции или типы , которые отличаются только набором типов, с которыми они работают при использовании, тем самым уменьшая дублирование кода .

Универсальное программирование стало массовым явлением вместе с Ada в 1977 году. С появлением шаблонов на C++ универсальное программирование стало частью репертуара профессионального проектирования библиотек. Техники были усовершенствованы, и параметризованные типы были представлены во влиятельной книге Design Patterns 1994 года . [3]

Новые методы были представлены Андреем Александреску в его книге 2001 года « Современный дизайн на C++: общее программирование и применение шаблонов проектирования» . Впоследствии D реализовал те же идеи.

Такие программные объекты известны как дженерики в Ada , C# , Delphi , Eiffel , F# , Java , Nim , Python , Go , Rust , Swift , TypeScript и Visual Basic .NET . Они известны как параметрический полиморфизм в ML , Scala , Julia и Haskell . (В терминологии Haskell также используется термин «общий» для обозначения родственной, но несколько иной концепции.)

Термин «обобщенное программирование» первоначально был придуман Дэвидом Массером и Александром Степановым. [4] в более конкретном смысле, чем указано выше, для описания парадигмы программирования, в которой фундаментальные требования к типам данных абстрагируются от конкретных примеров алгоритмов и структур данных и формализуются как концепции , с общими функциями , реализованными в терминах этих концепций, обычно с использованием языка механизмы универсальности, как описано выше.

Степанов-Мюссер и другие парадигмы общие программирования

Общее программирование определяется в Musser & Stepanov (1989) следующим образом:

Универсальное программирование основано на идее абстрагирования от конкретных эффективных алгоритмов для получения универсальных алгоритмов, которые можно комбинировать с различными представлениями данных для создания широкого спектра полезного программного обеспечения.

- Массер, Дэвид Р.; Степанов Александр А., Общее программирование. [5]

Парадигма «общего программирования» — это подход к декомпозиции программного обеспечения, при котором фундаментальные требования к типам абстрагируются от конкретных примеров алгоритмов и структур данных и формализуются в виде концепций , аналогично абстракции алгебраических теорий в абстрактной алгебре . [6] Ранние примеры этого подхода к программированию были реализованы в Scheme и Ada. [7] хотя наиболее известным примером является Стандартная библиотека шаблонов (STL), [8] [9] который разработал теорию итераторов , которая используется для разделения структур данных последовательностей и алгоритмов, работающих с ними.

Например, даны N структур данных последовательности, например, односвязный список, вектор и т. д., и M алгоритмов для работы с ними, например find, sortи т. д., прямой подход будет реализовывать каждый алгоритм специально для каждой структуры данных, давая N × M комбинаций для реализации. Однако в универсальном подходе к программированию каждая структура данных возвращает модель концепции итератора (простой тип значения, который можно разыменовать для получения текущего значения или изменить, чтобы он указывал на другое значение в последовательности), и вместо этого каждый алгоритм записывается в общем случае с аргументами таких итераторов, например, пары итераторов, указывающих на начало и конец подпоследовательности или диапазона для обработки. только N + M Таким образом, необходимо реализовать комбинаций структуры данных и алгоритма. В STL указано несколько концепций итераторов, каждая из которых является усовершенствованием более ограничительных концепций, например, итераторы прямого доступа обеспечивают только переход к следующему значению в последовательности (например, подходят для односвязного списка или потока входных данных), тогда как итераторы с произвольным доступом итератор также обеспечивает прямой доступ с постоянным временем к любому элементу последовательности (например, подходящему для вектора). Важным моментом является то, что структура данных будет возвращать модель самой общей концепции, которую можно эффективно реализовать — Требования к вычислительной сложности явно являются частью определения концепции. Это ограничивает структуры данных, к которым может применяться данный алгоритм, и такие требования к сложности являются основным фактором, определяющим выбор структуры данных. Общее программирование аналогичным образом применялось и в других областях, например, в графовых алгоритмах. [10]

Хотя этот подход часто использует языковые особенности универсальности и шаблонов во время компиляции , он не зависит от конкретных технических деталей языка. Пионер универсального программирования Александр Степанов писал:

Общее программирование — это абстрагирование и классификация алгоритмов и структур данных. Он черпает вдохновение у Кнута , а не из теории типов. Его цель — постепенное построение систематических каталогов полезных, эффективных и абстрактных алгоритмов и структур данных. Такое предприятие пока остается мечтой.

Александр Степанов, Краткая история STL [11] [12]

Я считаю, что теории итераторов так же важны для информатики, как теории колец или банаховых пространств являются центральными для математики.

Александр Степанов, Интервью с А. Степановым [13]

Бьёрн Страуструп отметил:

Следуя Степанову, мы можем определить общее программирование, не упоминая особенностей языка: Поднимите алгоритмы и структуры данных от конкретных примеров до их наиболее общей и абстрактной формы.

- Бьёрн Страуструп, Развитие языка в реальном мире и для него: C++ 1991-2006. [12]

Другие парадигмы программирования, которые были описаны как универсальное программирование, включают универсальное программирование типов данных , как описано в «Общее программирование – введение». [14] Подход «Отбросьте свой шаблон» — это облегченный универсальный подход к программированию для Haskell. [15]

, В этой статье мы отличаем парадигмы обобщенного программирования высокого уровня языка программирования нижнего уровня, описанные выше, от механизмов универсальности используемых для их реализации (см. Поддержка универсальности в языках программирования ). Дальнейшее обсуждение и сравнение общих парадигм программирования см. [16]

языка программирования для универсальности Поддержка

Средства обобщения существовали в языках высокого уровня, по крайней мере, с 1970-х годов в таких языках, как ML , CLU и Ada , и впоследствии были приняты многими объектно-ориентированными и объектно-ориентированными языками, включая BETA , C++ , D , Eiffel , Java , и Trellis ныне несуществующая компания DEC -Owl .

Универсальность реализуется и поддерживается по-разному в разных языках программирования; термин «общий» также использовался по-разному в различных контекстах программирования. Например, в Форте компилятор может выполнять код во время компиляции , и можно создавать новые ключевые слова компилятора на лету и новые реализации для этих слов. В нем мало слов , раскрывающих поведение компилятора, и поэтому он, естественно, предлагает возможности универсальности , которые, однако, не упоминаются как таковые в большинстве текстов на Форте. Точно так же динамически типизированные языки, особенно интерпретируемые, обычно предлагают универсальность по умолчанию, поскольку как передача значений в функции, так и присвоение значений не зависят от типа, и такое поведение часто используется для абстракции или краткости кода, однако это обычно не обозначается как универсальность , поскольку это прямое следствие системы динамической типизации, используемой в языке. [ нужна цитата ] Этот термин использовался в функциональном программировании , особенно в языках, подобных Haskell , которые используют систему структурных типов , где типы всегда являются параметрическими, а фактический код для этих типов является универсальным. Эти варианты использования по-прежнему служат той же цели: сохранения кода и визуализации абстракции.

Массивы и структуры можно рассматривать как предопределенные универсальные типы. Каждое использование типа массива или структуры создает экземпляр нового конкретного типа или повторно использует предыдущий созданный тип. Типы элементов массива и типы элементов структуры — это параметризованные типы, которые используются для создания экземпляра соответствующего универсального типа. Все это обычно встроено в компилятор и синтаксис отличается от других универсальных конструкций. Некоторые расширяемые языки программирования пытаются унифицировать встроенные и определяемые пользователем универсальные типы.

Далее следует широкий обзор механизмов универсальности в языках программирования. Конкретный обзор, сравнивающий пригодность механизмов для общего программирования, см. [17]

В объектно-ориентированных языках [ править ]

При создании классов-контейнеров в статически типизированных языках неудобно писать конкретные реализации для каждого содержащегося типа данных, особенно если код для каждого типа данных практически идентичен. Например, в C++ это дублирование кода можно обойти, определив шаблон класса:

template  <  typename   T  > 
 class   List   { 
   // Содержимое класса. 
  }; 

  List  <  Животное  >   list_of_animals  ; 
  List  <  Автомобиль  >   list_of_cars  ; 

Выше, Tявляется заполнителем для любого типа, указанного при создании списка. Эти «контейнеры типа T», обычно называемые шаблонами , позволяют повторно использовать класс с разными типами данных при условии определенных контрактов, таких как подтипы и подпись сохранения . Этот механизм универсальности не следует путать с полиморфизмом включения , который представляет собой алгоритмическое использование заменяемых подклассов: например, список объектов типа Moving_Object содержащий объекты типа Animal и Car. Шаблоны также можно использовать для независимых от типа функций, как в Swap пример ниже:

 ссылки 
// "&" обозначает шаблон  <  имя типа   T  > 
 void   Swap  (  T  &   a  ,   T  &   b  )   {   // Аналогичная, но более безопасная и потенциально более быстрая функция 
                         // определена в заголовке стандартной библиотеки <utility> 
   T   temp   =   б  ; 
    б   =   а  ; 
    а   =   температура  ; 
  } 

 std  ::  string   world   =   "Мир!"   ; 
  std  ::  string   hello   =   "Привет,"  ; 
  Обмен  (  мир  ,   привет  ); 
  std  ::  cout   <<   world   <<   hello   <<   '\  n  '  ;     // Вывод: «Привет, мир!». 

С++ template конструкция, использованная выше, широко цитируется [ нужна цитата ] как конструкция универсальности, которая популяризировала это понятие среди программистов и разработчиков языков и поддерживает множество общих идиом программирования. Язык программирования D также предлагает полностью универсальные шаблоны, основанные на прецеденте C++, но с упрощенным синтаксисом. Язык программирования Java предоставляет возможности обобщения, синтаксически основанные на C++, с момента появления платформы Java Standard Edition (J2SE) 5.0.

В C# 2.0, Oxygene 1.5 (ранее Chrome) и Visual Basic .NET 2005 есть конструкции, использующие поддержку универсальных шаблонов, присутствующих в Microsoft .NET Framework начиная с версии 2.0.

Дженерики в Ada [ править ]

Обобщенные коды Ada существуют с момента их первой разработки в 1977–1980 годах. Стандартная библиотека использует дженерики для предоставления множества сервисов. Ada 2005 добавляет к стандартной библиотеке комплексную библиотеку универсальных контейнеров, вдохновленную стандартной библиотекой шаблонов C++ .

Общий модуль — это пакет или подпрограмма, принимающая один или несколько общих формальных параметров . [18]

Общий формальный параметр — это значение, переменная, константа, тип, подпрограмма или даже экземпляр другой назначенной универсальной единицы. Для общих формальных типов синтаксис различает дискретные типы, типы с плавающей запятой, фиксированной запятой, типы доступа (указатели) и т. д. Некоторые формальные параметры могут иметь значения по умолчанию.

Чтобы создать экземпляр универсального модуля, программист передает фактические параметры для каждого формального элемента. В этом случае универсальный экземпляр ведет себя так же, как и любой другой модуль. Можно создавать экземпляры универсальных модулей во время выполнения , например, внутри цикла.

Пример [ править ]

Спецификация универсального пакета:

 общий 
     Max_Size   :   Natural  ;    -- общий 
     тип   формального значения Element_Type   является   частным  ;    -- общий формальный тип;  неограниченного типа. 
   принимает любой пакет   Стеки   имеют 
     тип   Size_Type    диапазон   0   ..   Max_Size  ; 
      тип   стека   ограничен   частным   ; 
      процедура   Create   (  S   :  out   Stack  ; 
                       Initial_Size   :  in   Size_Type   :=   Max_Size  ); 
      процедура   Push   (  Into   :  in   out   Stack  ;   Element   :  in   Element_Type  ); 
      процедура   Pop   (  From   :  in   out   Stack  ;   Element   :  out   Element_Type  ); 
      Переполнение   :   исключение  ; 
      Недополнение   :   исключение  ; 
   частный 
     подтип   Index_Type   — это   Size_Type   диапазон   1   ..   Max_Size  ; 
      type   Vector   — это   массив   (  Index_Type   диапазон   <>)   из   Element_Type  ; 
      тип   Stack   (  Allocated_Size   :  Size_Type   :=   0  )   — это   запись 
        Top   :   Index_Type  ; 
         Хранилище   :   векторное   (  1   ..   Allocated_Size  ); 
      завершить запись  ; 
   конец   стеков  ; 

Создание экземпляра общего пакета:

 тип   Bookmark_Type   новый    Natural  ; 
   -- записывает местоположение в текстовом документе, который мы редактируем. 

  package   Bookmark_Stacks   is new   Stacks   (  Max_Size   =>  20  , 
                                         Element_Type   =>  Bookmark_Type  ); 
   -- Позволяет пользователю переключаться между записанными местами в документе. 

Использование экземпляра универсального пакета:

 type   Document_Type   — это   запись. 
     Содержание   :   Ada  .   Струны  .   Неограниченный  .   Неограниченная_Строка  ; 
      Закладки   :   Bookmark_Stacks  .   Куча  ; 
   завершить запись  ; 

   процедура   Edit   (  Document_Name   :  in   String  )  
    Document   :   Document_Type  ; 
   начало 
    — Инициализировать стек закладок: 
    Bookmark_Stacks  .   Создать   (  S   =>   Document  .  Bookmarks  ,   Initial_Size   =>   10  ); 
     -- Теперь откройте файл Document_Name и прочитайте его... 
  end   Edit  ; 
Преимущества и ограничения [ править ]

Синтаксис языка позволяет точно указать ограничения на общие формальные параметры. Например, можно указать, что универсальный формальный тип будет принимать в качестве фактического только модульный тип. Также возможно выразить ограничения между общими формальными параметрами; например:

 универсальный 
     тип   Index_Type   равен   (<>);    -- должен быть дискретным типом. 
     Тип   Element_Type   является   частным  ;    -- может быть любым неограниченным типом 
     .   Array_Type   — это   массив   (  Index_Type   диапазон   <>)   из   Element_Type  ; 

В этом примере Array_Type ограничен как Index_Type, так и Element_Type. При создании экземпляра модуля программист должен передать фактический тип массива, удовлетворяющий этим ограничениям.

Недостатком этого детального управления является сложный синтаксис, но, поскольку все формальные параметры обобщения полностью определены в спецификации, компилятор может создавать экземпляры обобщений, не просматривая тело обобщения.

В отличие от C++, Ada не допускает создания специализированных обобщенных экземпляров и требует, чтобы все обобщенные экземпляры создавались явно. Эти правила имеют несколько последствий:

  • компилятор может реализовать общие дженерики : объектный код для универсального модуля может использоваться всеми экземплярами (конечно, если программист не запрашивает встраивание подпрограмм). В качестве дальнейших последствий:
    • нет возможности раздувания кода (раздувание кода часто встречается в C++ и требует особого внимания, как описано ниже).
    • можно создавать экземпляры дженериков во время выполнения и во время компиляции, поскольку для нового экземпляра не требуется новый объектный код.
    • фактические объекты, соответствующие общему формальному объекту, всегда считаются нестатическими внутри общего; подробности и последствия см . в разделе «Общие формальные объекты» в Wikibook.
  • поскольку все экземпляры обобщенного кода совершенно одинаковы, легче просматривать и понимать программы, написанные другими; нет никаких «особых случаев», которые следует принимать во внимание.
  • все экземпляры являются явными, нет никаких скрытых экземпляров, которые могли бы затруднить понимание программы.
  • Ada не допускает произвольных вычислений во время компиляции, поскольку операции с общими аргументами выполняются во время выполнения.

Шаблоны на C++ [ править ]

C++ использует шаблоны для реализации общих методов программирования. Стандартная библиотека C++ включает в себя стандартную библиотеку шаблонов или STL, которая предоставляет структуру шаблонов для общих структур данных и алгоритмов. Шаблоны в C++ также могут использоваться для метапрограммирования шаблонов , что представляет собой способ предварительной оценки части кода во время компиляции, а не во время выполнения . Благодаря специализации шаблонов шаблоны C++ являются полными по Тьюрингу .

Технический обзор [ править ]

Существует множество типов шаблонов, наиболее распространенными из которых являются шаблоны функций и шаблоны классов. Шаблон функции — это шаблон для создания обычных функций на основе типов параметризации, предоставляемых при создании экземпляра. Например, стандартная библиотека шаблонов C++ содержит шаблон функции max(x, y) который создает функции, возвращающие либо x , либо y, в зависимости от того, какое значение больше. max() можно определить так:

шаблон  <  имя типа   T  > 
 T   max  (  T   x  ,   T   y  )   { 
   return   x   <   y   ?    у   :   х  ; 
  } 

Специализации этого шаблона функции, экземпляры определенных типов, можно вызывать так же, как обычную функцию:

std  ::  cout   <<   max  (  3  ,   7  );     // Выходы 7. 

Компилятор проверяет аргументы, используемые для вызова max и определяет, что это вызов max(int, int). Затем он создает экземпляр версии функции, в которой тип параметризации T является int, что делает эквивалент следующей функции:

int   max  (  int   x  ,   int   y  )   { 
   return   x   <   y   ?    у   :   х  ; 
  } 

Это работает, независимо от того, аргументы x и y являются целыми числами, строками или любым другим типом, для которого выражение x < y разумно или, более конкретно, для любого типа, для которого operator<определено. Общее наследование не требуется для набора типов, которые можно использовать, поэтому оно очень похоже на утиную типизацию . Программа, определяющая пользовательский тип данных, может использовать перегрузку операторов , чтобы определить значение < для этого типа, что позволяет использовать его с max()шаблон функции. Хотя в этом изолированном примере это может показаться незначительным преимуществом, в контексте такой комплексной библиотеки, как STL, это позволяет программисту получить обширную функциональность для нового типа данных, просто определив для него несколько операторов. Просто определение < позволяет использовать тип со стандартным sort(), stable_sort(), и binary_search() алгоритмы или помещаться внутри структур данных, таких как sets, кучи и ассоциативные массивы .

Шаблоны C++ полностью типобезопасны во время компиляции. В качестве демонстрации стандартный тип complex не определяет < нет строгого порядка оператор, поскольку для комплексных чисел . Поэтому, max(x, y) завершится ошибкой компиляции, если x и y равны complexценности. Аналогично, другие шаблоны, основанные на < не может быть применен к complexданные, если не предусмотрено сравнение (в форме функтора или функции). Например: А complex не может быть использован в качестве ключа для mapесли не будет сравнения. К сожалению, исторически компиляторы генерируют несколько эзотерические, длинные и бесполезные сообщения об ошибках такого рода. Обеспечение соответствия определенного объекта протоколу метода может решить эту проблему. Языки, которые используют compare вместо < также можно использовать complex значения как ключи.

Другой тип шаблона — шаблон класса — распространяет ту же концепцию на классы. Специализация шаблона класса — это класс. Шаблоны классов часто используются для создания универсальных контейнеров. Например, в STL есть контейнер связанного списка . Чтобы создать связанный список целых чисел, пишут list<int>. Список строк обозначается list<string>. А list имеет набор связанных с ним стандартных функций, которые работают для любых совместимых типов параметризации.

Специализация шаблона [ править ]

Мощной особенностью шаблонов C++ является специализация шаблонов . Это позволяет предоставлять альтернативные реализации на основе определенных характеристик параметризованного типа, экземпляр которого создается. Специализация шаблонов преследует две цели: обеспечить определенные формы оптимизации и уменьшить раздувание кода.

Например, рассмотрим sort()функция шаблона. Одним из основных действий, выполняемых такой функцией, является замена значений в двух позициях контейнера. Если значения большие (с точки зрения количества байтов, необходимых для хранения каждого из них), то часто бывает быстрее сначала создать отдельный список указателей на объекты, отсортировать эти указатели, а затем построить окончательную отсортированную последовательность. . Однако если значения довольно малы, обычно быстрее всего просто поменять местами значения по мере необходимости. Более того, если параметризованный тип уже относится к некоторому типу указателя, нет необходимости создавать отдельный массив указателей. Специализация шаблона позволяет создателю шаблона писать различные реализации и указывать характеристики, которые параметризованный тип(ы) должен иметь для каждой используемой реализации.

В отличие от шаблонов функций, шаблоны классов могут быть частично специализированными . Это означает, что альтернативная версия кода шаблона класса может быть предоставлена, когда некоторые параметры шаблона известны, оставляя при этом другие параметры шаблона общими. Это можно использовать, например, для создания реализации по умолчанию ( основная специализация ), которая предполагает, что копирование параметризуемого типа является дорогостоящим, а затем создать частичные специализации для типов, копировать которые дешево, тем самым увеличивая общую эффективность. Клиенты такого шаблона класса просто используют его специализации без необходимости знать, использовал ли компилятор в каждом случае первичную специализацию или некоторую частичную специализацию. Шаблоны классов также могут быть полностью специализированными, а это означает, что альтернативная реализация может быть предоставлена, когда известны все типы параметризации.

Преимущества и недостатки [ править ]

Некоторые варианты использования шаблонов, например max()ранее заполнялись препроцессора макросами , похожими на функции (наследие языка C ). Например, вот возможная реализация такого макроса:

#define max(a,b) ((a) < (b) ? (b) : (a)) 

Макросы расширяются (копируются) препроцессором перед правильной компиляцией; шаблоны — это настоящие реальные функции. Макросы всегда раскрываются в строке; шаблоны также могут быть встроенными функциями , если компилятор сочтет это целесообразным.

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

Есть четыре основных недостатка использования шаблонов: поддерживаемые функции, поддержка компилятора, плохие сообщения об ошибках (обычно с SFINAE до C++20 ) и раздувание кода :

  1. В шаблонах C++ отсутствуют многие функции, что делает их реализацию и использование простым способом зачастую невозможным. Вместо этого программистам приходится полагаться на сложные приемы, что приводит к раздутому, трудному для понимания и сопровождению коду. Текущие разработки в стандартах C++ усугубляют эту проблему, активно используя эти приемы и создавая множество новых функций для шаблонов на их основе или с их учетом.
  2. Многие компиляторы исторически плохо поддерживали шаблоны, поэтому использование шаблонов могло сделать код несколько менее переносимым. Поддержка также может быть плохой, если компилятор C++ используется с компоновщиком , не поддерживающим C++, или при попытке использовать шаблоны за пределами разделяемых библиотек .
  3. Компиляторы могут выдавать запутанные, длинные и иногда бесполезные сообщения об ошибках, когда ошибки обнаруживаются в коде, использующем SFINAE. [19] Это может затруднить разработку шаблонов.
  4. Наконец, использование шаблонов требует, чтобы компилятор генерировал отдельный экземпляр шаблонного класса или функции для каждого параметра типа, используемого с ним. (Это необходимо, поскольку не все типы в C++ имеют одинаковый размер, а размеры полей данных важны для работы классов.) Таким образом, неразборчивое использование шаблонов может привести к раздуванию кода , что приведет к созданию чрезмерно больших исполняемых файлов. Однако разумное использование специализации и производных шаблонов может в некоторых случаях значительно уменьшить такое раздувание кода:

    Итак, можно ли использовать деривацию для уменьшения проблемы репликации кода из-за использования шаблонов? Это потребует получения шаблона от обычного класса. Этот метод оказался успешным в борьбе с раздуванием кода в реальном использовании. Люди, которые не используют подобную технику, обнаружили, что реплицируемый код может занимать мегабайты кодового пространства даже в программах среднего размера.

    - Бьёрн Страуструп , Проектирование и эволюция C++, 1994 г. [20]
  5. Шаблонные классы или функции могут потребовать явной специализации класса шаблона, что потребует переписывания всего класса для конкретных параметров шаблона, используемых им.

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

Кроме того, исходный код реализации шаблона должен быть полностью доступен (например, включен в заголовок) для использующей его единицы перевода (исходного файла). Шаблоны, включая большую часть стандартной библиотеки, если они не включены в файлы заголовков, не могут быть скомпилированы. (В отличие от нешаблонного кода, который может быть скомпилирован в двоичный формат, предоставляя только файл заголовка объявлений для кода, использующего его.) Это может быть недостатком, поскольку раскрывается код реализации, который удаляет некоторые абстракции и может ограничить его. использование в проектах с закрытым исходным кодом. [ нужна цитата ]

Шаблоны в D [ править ]

Язык D поддерживает шаблоны, основанные на C++. Большинство идиом шаблонов C++ работают в D без изменений, но D добавляет некоторые функциональные возможности:

  • Параметры шаблона в D не ограничиваются только типами и примитивными значениями (как это было в C++ до C++20), но также допускают произвольные значения времени компиляции (например, строки и структурные литералы) и псевдонимы произвольных идентификаторов, включая другие шаблоны или экземпляры шаблонов.
  • Ограничения шаблона и static if предоставляют альтернативу концепциям C++ C++ и if constexpr.
  • The is(...) Выражение позволяет спекулятивное создание экземпляров для проверки свойств объекта во время компиляции.
  • The auto ключевое слово и typeof выражения позволяют выводить тип для объявлений переменных и возвращаемых значений функций, что, в свою очередь, допускает «типы Волдеморта» (типы, не имеющие глобального имени). [21]

Шаблоны в D используют другой синтаксис, чем в C++: тогда как в C++ параметры шаблона заключаются в угловые скобки ( Template<param1, param2>), D использует восклицательный знак и круглые скобки: Template!(param1, param2). Это позволяет избежать трудностей синтаксического анализа C++ из-за неоднозначности операторов сравнения. Если параметр только один, круглые скобки можно опустить.

Традиционно D объединяет вышеперечисленные функции для обеспечения полиморфизма во время компиляции с использованием универсального программирования на основе признаков. Например, диапазон ввода определяется как любой тип, который удовлетворяет проверкам, выполняемым isInputRange, который определяется следующим образом:

template   isInputRange  (  R  ) 
 { 
     enum   bool   isInputRange   =   is  (  typeof  ( 
     (  inout   int   =   0  ) 
     { 
         R   r   =   R  .  init  ;       // можно определить объект диапазона 
         if   (  r  .  пустой  )   {}     // можно проверить пустой 
         r  .  popFront  ();       // можем вызвать popFront() 
         auto   h   =   r  .  front  ;   // можем получить начало диапазона 
     })); 
  } 

Функция, которая принимает только входные диапазоны, может затем использовать приведенный выше шаблон в ограничении шаблона:

auto   fun  (  Диапазон  )(  диапазона   Диапазон  ) 
     if   (  isInputRange  !  Диапазон  ) 
 { 
     // ... 
 } 
Генерация кода [ править ]

В дополнение к метапрограммированию шаблонов, D также предоставляет несколько функций, позволяющих генерировать код во время компиляции:

  • The import выражение позволяет читать файл с диска и использовать его содержимое в виде строкового выражения.
  • Отражение во время компиляции позволяет перечислять и проверять объявления и их члены во время компиляции.
  • Пользовательские атрибуты позволяют пользователям присоединять к объявлениям произвольные идентификаторы, которые затем можно перечислять с помощью отражения во время компиляции.
  • Выполнение функции во время компиляции (CTFE) позволяет интерпретировать подмножество D (ограниченное безопасными операциями) во время компиляции.
  • Строковые миксины позволяют оценивать и компилировать содержимое строкового выражения в виде D-кода, который становится частью программы.

Объединение вышеизложенного позволяет генерировать код на основе существующих объявлений. Например, платформы сериализации D могут перечислять члены типа и генерировать специализированные функции для каждого сериализованного типа. для выполнения сериализации и десериализации. Определенные пользователем атрибуты могут дополнительно указывать правила сериализации.

The importВыполнение выражений и функций во время компиляции также позволяет эффективно реализовывать языки, специфичные для предметной области . Например, если есть функция, которая принимает строку, содержащую шаблон HTML, и возвращает эквивалентный исходный код D, ее можно использовать следующим образом:

// Импортируем содержимое example.htt как строковую константу манифеста. 
  enum   htmlTemplate   =   import  (  «example.htt»  ); 

  // Транспилируем HTML-шаблон в D-код. 
  перечисление   htmlDCode   =   htmlTemplateToD  (  htmlTemplate  ); 

  // Вставляем содержимое htmlDCode как D-код. 
  миксин  (  htmlDCode  ); 

Генеричность в Эйфелевой системе [ править ]

Универсальные классы были частью Eiffel с момента создания оригинального метода и языка. Основополагающие публикации Эйфеля, [22] [23] используйте термин универсальность для описания создания и использования универсальных классов.

Базовая, неограниченная универсальность [ править ]

Универсальные классы объявляются с указанием имени класса и списка одного или нескольких формальных универсальных параметров . В следующем коде класс LIST имеет один формальный общий параметр G

class 
     LIST   [  G  ] 
             ... 
 Feature     — Доступ к 
     элементу  :   G 
             — Элемент, на который в данный момент указывает курсор 
             ... 
 Feature     — Изменение элемента 
     put   (  new_item  :   G  ) 
             — Добавить `new_item' в конец списка 
             ... 

Формальные универсальные параметры — это заполнители для произвольных имен классов, которые будут предоставлены при объявлении универсального класса, как показано в двух обобщенных производных классах ниже, где ACCOUNT и DEPOSIT другие имена классов. ACCOUNT и DEPOSIT считаются фактическими универсальными параметрами , поскольку они предоставляют реальные имена классов для замены G в реальном использовании.

    list_of_accounts  :   LIST   [  ACCOUNT  ] 
             -- Список счетов 

     list_of_deposits  :   LIST   [  DEPOSIT  ] 
             -- Список депозитов 

В системе типов Эйфеля, хотя класс LIST [G]считается классом, а не типом. Однако общий вывод LIST [G] такой как LIST [ACCOUNT] считается типом.

Ограниченная универсальность [ править ]

Для класса списка, показанного выше, фактический универсальный параметр, заменяющий Gможет быть любой другой доступный класс. Чтобы ограничить набор классов, из которых можно выбрать действительные фактические универсальные параметры, универсальное ограничение можно указать . В объявлении класса SORTED_LIST ниже универсальное ограничение требует, чтобы любой действительный фактический универсальный параметр был классом, наследуемым от класса COMPARABLE. Общее ограничение гарантирует, что элементы SORTED_LIST на самом деле можно отсортировать.

класс 
     SORTED_LIST   [  G   ->   СРАВНЕННЫЙ  ] 

Дженерики в Java [ править ]

Поддержка дженериков или «контейнеров типа T» была добавлена ​​в язык программирования Java в 2004 году как часть J2SE 5.0. В Java дженерики проверяются только во время компиляции на правильность типа. Информация об общем типе затем удаляется с помощью процесса, называемого стиранием типа , для обеспечения совместимости со старыми JVM , что делает ее недоступной во время выполнения. реализациями [24] Например, List<String> преобразуется в необработанный тип List. Компилятор вставляет приведение типов для преобразования элементов в String type при их извлечении из списка, что снижает производительность по сравнению с другими реализациями, такими как шаблоны C++.

Универсальность в .NET [C#, VB.NET] [ править ]

Универсальные шаблоны были добавлены как часть .NET Framework 2.0 в ноябре 2005 года на основе исследовательского прототипа, проведенного Microsoft Research, начатого в 1999 году. [25] Хотя дженерики .NET аналогичны дженерикам в Java, они не применяют стирание типов . [26] : 208–209  но реализуйте дженерики как первоклассный механизм во время выполнения, используя реификацию . Этот выбор дизайна обеспечивает дополнительные функциональные возможности, такие как возможность отражения с сохранением универсальных типов и смягчение некоторых ограничений стирания (например, невозможность создания универсальных массивов). [27] [28] не влияют на производительность Это также означает, что приведение типов во время выполнения и обычно дорогостоящие преобразования упаковки . Когда примитивные типы и типы значений используются в качестве универсальных аргументов, они получают специализированные реализации, позволяющие создавать эффективные универсальные коллекции и методы. Как и в C++ и Java, вложенные универсальные типы, такие как Dictionary<string, List<int>>, являются допустимыми типами, однако их не рекомендуется использовать для подписей членов в правилах проектирования анализа кода. [29]

.NET допускает шесть разновидностей ограничений универсального типа, используя where ключевое слово, включая ограничение универсальных типов типами значений, классами, наличием конструкторов и реализацией интерфейсов. [30] Ниже приведен пример с ограничением интерфейса:

используя   систему  ; 

  класс   Sample 
 { 
     static   void   Main  () 
     { 
         int  []   array   =   {   0  ,   1  ,   2  ,   3   }; 
          MakeAtLeast  <int>  2  (  массив  ,   )  ;    // Изменить массив на { 2, 2, 2, 3 } 
         foreach   (  int   i   in   array  ) 
             Console  .   WriteLine  (  я  );    // Печать результатов. 
          Консоль  .   ReadKey  (  истина  ); 
      } 

     static   void   MakeAtLeast  <T>  list  где  (  T  []   ,  T   самый   )  ,   T   :   IComparable   <T>  {  if  ; 
     for 
         (   int  i   =   0   ;  i   <   length   .  (  i  список   ++  )  , 
             (   list  [  i  ]  .  CompareTo  низкий  самый низкий  )   <   0  ) 
                 список  [  я  ]   =   самый низкий  ; 
      } 
 } 

The MakeAtLeast() метод позволяет работать с массивами с элементами универсального типа T. Ограничение типа метода указывает, что метод применим к любому типу. T который реализует общий IComparable<T>интерфейс. Это гарантирует ошибку времени компиляции , если метод вызывается, если тип не поддерживает сравнение. Интерфейс предоставляет общий метод CompareTo(T).

Вышеупомянутый метод также можно написать без универсальных типов, просто используя необобщенный тип. Arrayтип. Однако, поскольку массивы являются контравариантными , приведение типов не будет безопасным , и компилятор не сможет обнаружить определенные возможные ошибки, которые в противном случае были бы обнаружены при использовании универсальных типов. Кроме того, методу потребуется доступ к элементам массива как objects вместо этого и потребует приведения для сравнения двух элементов. (Для таких типов значений, как int для этого требуется преобразование бокса , хотя это можно обойти с помощью Comparer<T> class, как это делается в стандартных классах коллекций.)

Примечательным поведением статических членов в универсальном классе .NET является создание экземпляра статического члена для каждого типа времени выполнения (см. пример ниже).

    // Общий класс 
     public   class   GenTest  <  T  > 
     { 
         // Статическая переменная - будет создана для каждого типа при отражении 
         static   CountedInstances   OnePerType   =   new   CountedInstances  (); 

          // член данных 
         Private   T   _t  ; 

          // простой конструктор 
         public   GenTest  (  T   t  ) 
         { 
             _t   =   t  ; 
          } 
     } 

     // класс 
     public   class   CountedInstances 
     { 
         // Статическая переменная — она будет увеличиваться один раз для каждого экземпляра 
         public   static   int   Counter  ; 

          //простой конструктор 
         public   CountedInstances  () 
         { 
             //увеличиваем счетчик на единицу во время создания экземпляра объекта 
             CountedInstances  .   Счетчик  ++  ; 
          } 
     } 

 // точка входа в основной код 
 // в конце выполнения CountedInstances.Counter = 2 
 GenTest  <  int  >   g1   =   new   GenTest  <  int  >  (  1  ); 
  GenTest  <int>  g11    =   новый   GenTest  <int>  11  (  )  ; 
  GenTest  <int>   g111   =   новый   GenTest  <int>  111  (  )  ; 
  GenTest  <double>   g2   =   новый   GenTest  <double>  1.0  (  )  ; 

Универсальность в Delphi [ править ]

Диалект Delphi Object Pascal приобрел дженерики в выпуске Delphi 2007, первоначально только с компилятором .NET (сейчас прекращено), а затем был добавлен в собственный код в выпуске Delphi 2009. Семантика и возможности дженериков Delphi во многом смоделированы на основе дженериков в .NET 2.0, хотя реализация по необходимости совершенно другая. Вот более или менее прямой перевод первого примера C#, показанного выше:

 программы  Образец  ; 

  {$APPTYPE CONSOLE} 

 использует 
   дженерики  .   По умолчанию  ;   для 

 тип 
   TUtils   =   класс 
     class   процедура   MakeAtLeast  <T>  <T>  >  (  Arr  :   TArray  ;  :   const   Lowest  <   T  ; 
       Comparer  :   IComparer  <T>  ;   //  )  IComparer    перегрузка  ; 
     класса    процедура   MakeAtLeast  <T>  (  Arr  :   TArray  <T>  ;   const   Lowest  :   T  )  ;    перегрузка  ; 
    конец  ; 

 класса    процедура   TUtils  .   MakeAtLeast  <T>  (  Arr  :   TArray  <T>  :  ;   const   Lowest   T  ; 
   Comparer  :   IComparer  <T>  ;  ) 
  вар 
   I  :   Целое число  ; 
  начать 
   , если   Comparer   =   nil   , тогда   Comparer   :=   TComparer  <  T  >.   По умолчанию  ; 
    for   I   :=   Low  (  Arr  )   to   High  (  Arr  )   сделайте 
     if   Comparer  .   Сравните  (  Arr  [  I  ]  ,   Самый низкий  )   <   0,   тогда 
       Arr  [  I  ]   :=   Самый низкий  ; 
  конец  ; 

 класса    процедура   TUtils  .   MakeAtLeast  <T>  (  Arr  :   TArray  <T>  ;   const   Lowest  :   T  )  ; 
  начать 
   MakeAtLeast  <T>  ноль  (  Arr  ,   низкий  ,   Самый  )  ; 
  конец  ; 

  var 
   Ints  :   TArray  <  Целое число  >; 
    Значение  :   Целое число  ; 
  начало 
   Ints   :=   TArray  <  Целое число  >.   Создать  (  0  ,   1  ,   2  ,   3  )  ; 
    TUtils  .   MakeAtLeast  <Integer>  (  Ints  ,   2  )  ; 
    для   значения   в   Ints   do 
     WriteLn  (  Value  )  ; 
    ЧитатьЛн  ; 
  конец  . 

Как и в C#, методы и целые типы могут иметь один или несколько параметров типа. В этом примере TArray — это универсальный тип (определяемый языком), а MakeAtLeast — универсальный метод. Доступные ограничения очень похожи на доступные ограничения в C#: любой тип значения, любой класс, конкретный класс или интерфейс и класс с конструктором без параметров. Множественные ограничения действуют как аддитивный союз.

Универсальность во Free Pascal [ править ]

В Free Pascal дженерики были реализованы до Delphi, с другим синтаксисом и семантикой. Однако, начиная с версии FPC 2.6.0, синтаксис в стиле Delphi доступен при использовании языкового режима {$mode Delphi}. Таким образом, код Free Pascal поддерживает дженерики в любом стиле.

Пример Delphi и Free Pascal:

 стиля Delphi 
// модуль   A  ; 

 ifdef fpc} 
   {$mode delphi} 
 {$endif 

 интерфейса 

 тип 
   TGenericClass  <T>  T  =    { $   класса 
     функция   Foo  (  const   AValue  :   T  )  :   }  ; 
    конец  ; 

 реализации 

  функция   TGenericClass  <T>  .   Foo  (  const   AValue  :   T  )  :   T  ; 
  начало 
   результата   :=   AValue   +   AValue  ; 
  конец  ; 

  конец  . 

  // Стиль ObjFPC Free Pascal 
 unit   B  ; 

  {$ifdef fpc} 
   $mode objfpc} 
 {$endif 

 интерфейса 

 тип 
   общий   TGenericClass  <T>  }  =   функция   класса 
     Foo   T  (  const   AValue  :   T  )  :   {  ; 
    конец  ; 

 реализации 

  функция   TGenericClass  .   Foo  (  const   AValue  :   T  )  :   T  ; 
  начало 
   результата   :=   AValue   +   AValue  ; 
  конец  ; 

  конец  . 

 в стиле Delphi 
  // пример использования, программа   TestGenDelphi  ; 

  {$ifdef fpc} 
   {$mode delphi} 
 {$endif} 

 использует 
   A  ,  B  ; 

  вар 
   GC1  :   A.   TGenericClass  <  Целое число  >; 
    ГК2  :   Б.   TGenericClass  <  строка  >; 
  начать 
   GC1   :=   A  .   TGenericClass  <  Целое число  >.   Создавать  ; 
    GC2   :=   B  .   TGenericClass  <  строка  >.   Создавать  ; 
    WriteLn  (  GC1.Foo  100  (  )  )  ;    // 200 
   WriteLn  (  GC2.Foo  '  привет  (  '  ))  ;    // привет, привет 
   GC1  .   Бесплатно  ; 
    ГК2  .   Бесплатно  ; 
  конец  . 

 в стиле ObjFPC 
  // пример использования, программа   TestGenDelphi  ; 

  {$ifdef fpc} 
   {$mode objfpc} 
 {$endif} 

 использует 
   A  ,  B  ; 

  // требуется в 
 типе 
   TAGenericClassInt   =   specialize   A.  ObjFPC   TGenericClass  <  Целое число  >; 
    TBGenericClassString   =   специализировать   B  .   TGenericClass  <  строка  >; 
  вар 
  GC1  :   TAGenericClassInt  ; 
    GC2  :   TBGenericClassString  ; 
  начать 
   GC1   :=   TAGenericClassInt  .   Создавать  ; 
    GC2   :=   TBGenericClassString  .   Создавать  ; 
    WriteLn  (  GC1.Foo  100  (  )  )  ;    // 200 
   WriteLn  (  GC2.Foo  '  привет  (  '  ))  ;    // привет, привет 
   GC1  .   Бесплатно  ; 
    ГК2  .   Бесплатно  ; 
  конец  . 

Функциональные языки [ править ]

Универсальность в Haskell [ править ]

Механизм классов типов Haskell . поддерживает обобщенное программирование Шесть предопределенных классов типов в Haskell (включая Eq, типы, которые можно сравнивать на равенство, и Show, типы, значения которых могут отображаться как строки) обладают специальным свойством поддержки производных экземпляров. Это означает, что программист, определяющий новый тип, может заявить, что этот тип должен быть экземпляром одного из этих специальных классов типов, не предоставляя реализации методов класса, как это обычно необходимо при объявлении экземпляров класса. Все необходимые методы будут «производными», то есть построенными автоматически, на основе структуры типа. Например, следующее объявление типа двоичных деревьев утверждает, что он должен быть экземпляром классов Eq и Show:

данные   BinTree   a   =   Лист   a   |    Узел   (  BinTree   a  )   a   (  BinTree   a  ) 
       вывод   (  Eq  ,   Show  ) 

Это приводит к функции равенства ( ==) и функция строкового представления ( show) автоматически определяется для любого типа формы BinTree T при условии, что T сам поддерживает эти операции.

Поддержка производных экземпляров Eq и Show делает свои методы == и showуниверсальными, качественно отличными от параметрически полиморфных функций: эти «функции» (точнее, семейства функций с индексированным типом) могут применяться к значениям различных типов, и хотя они ведут себя по-разному для каждого типа аргумента, требуется небольшая работа, чтобы добавить поддержку нового типа. Ральф Хинце (2004) показал, что аналогичный эффект может быть достигнут для классов типов, определяемых пользователем, с помощью определенных методов программирования. Другие исследователи предложили подходы к этому и другим видам универсальности в контексте Haskell и расширений Haskell (обсуждаемых ниже).

ПолиП [ править ]

PolyP был первым универсальным расширением языка программирования для Haskell . В PolyP общие функции называются политипическими . В языке представлена ​​специальная конструкция, в которой такие политипические функции могут быть определены посредством структурной индукции по структуре функтора шаблона регулярного типа данных. Обычные типы данных в PolyP являются подмножеством типов данных Haskell. Обычный тип данных t должен иметь вид * → * , и если a является аргументом формального типа в определении, то все рекурсивные вызовы t должны иметь форму ta . Эти ограничения исключают типы данных более высокого порядка и вложенные типы данных, где рекурсивные вызовы имеют другую форму. Функция Flatten в PolyP представлена ​​в качестве примера:

   Flatten   ::   Regular   d   =>   d   a   ->   [  a  ] 
    ​​Flatten   =   cata   fl 

    политипический   fl   ::   f   a   [  a  ]   ​​->   [  a  ] 
      ​​case   f   of 
        g  +  h   ->   либо   fl   fl 
        g  *  h   ->   \  (  x  ,  y  )   ->   fl   x   ++   fl   y 
        ()   ->   \  x   ->   [] 
        Par   ->   \  x   ->   [  x  ] 
        Rec   ->   \  x   ->   x 
        d  @  g   ->   concat   .    сгладить   .    pmap   fl 
        Con   t   ->   \  x   ->   [] 

    cata   ::   Regular   d   =>   (  FunctorOf   d   a   b   ->   b  )   ->   d   a   ->   b 
Общий Haskell [ править ]

Generic Haskell — еще одно расширение Haskell , разработанное в Утрехтском университете в Нидерландах . Расширения, которые он предоставляет:

  • Значения с индексированием типа определяются как значения, индексированные по различным конструкторам типов Haskell (единица измерения, примитивные типы, суммы, продукты и конструкторы пользовательских типов). Кроме того, мы также можем указать поведение индексированных по типу значений для конкретного конструктора, используя случаи конструктора , и повторно использовать одно общее определение в другом, используя случаи по умолчанию .

Результирующее значение с индексом типа может быть специализировано для любого типа.

  • Типы с индексацией по типу — это типы, индексированные по видам, определенные путем указания регистра как для *, так и для k → k' . Экземпляры получаются путем применения типа, индексированного по виду, к виду.
  • Общие определения можно использовать, применяя их к типу или виду. Это называется универсальным приложением . Результатом является тип или значение, в зависимости от того, какое универсальное определение применяется.
  • Универсальная абстракция позволяет определять универсальные определения путем абстрагирования параметра типа (заданного типа).
  • Типы с индексацией типа — это типы, которые индексируются по конструкторам типов. Их можно использовать для присвоения типов более сложным универсальным значениям. Получающиеся в результате типы с индексацией типа могут быть специализированы для любого типа.

В качестве примера функция равенства в Generic Haskell: [31]

   тип   Eq   {[   *   ]}   t1   t2   =   t1   ->   t2   ->   Bool 
    тип   Eq   {[   k   ->   l   ]}   t1   t2   =   forall   u1   u2  .    Уравнение   {[   k   ]}   u1   u2   ->   Уравнение   {[   l   ]}   (  t1   u1  )   (  t2   u2  ) 

    eq   {  |    т   ::   к   |   }   ::   Eq   {[   k   ]}   t   t 
    eq   {  |    Единица   |   }   _   _   =   Истинное 
    уравнение   {  |    :+:   |   }   eqA   eqB   (  Inl   a1  )   (  Inl   a2  )   знак равно   eqA   a1   a2 
    eq   {  |    :+:   |   }   eqA   eqB   (  Inr   b1  )   (  Inr   b2  )   знак равно   eqB   b1   b2 
    eq   {  |    :+:   |   }   eqA   eqB   _   _   =   Ложное 
    eq   {  |    :*:   |   }   eqA   eqB   (  a1   :*:   b1  )   (  a2   :*:   b2  )   =   eqA   a1   a2   &&   eqB   b1   b2 
    eq   {  |    Интер   |   }   =   (  ==  ) 
    экв   {  |    Чар   |   }   =   (  ==  ) 
    экв   {  |    Бул   |   }   =   (  ==  ) 

Чистый [ править ]

Clean предлагает универсальное программирование на основе PolyP и Generic Haskell , поддерживаемое GHC ≥ 6.0. Он параметризуется по типу, но предлагает перегрузку.

Другие языки [ править ]

Языки семейства ML поддерживают универсальное программирование посредством параметрического полиморфизма и универсальных модулей , называемых функторами. И Standard ML , и OCaml предоставляют функторы, похожие на шаблоны классов и универсальные пакеты Ada. Синтаксические абстракции схем также связаны с универсальностью — на самом деле они являются расширенным набором шаблонов C++.

Модуль Verilog может принимать один или несколько параметров, которым при создании экземпляра модуля присваиваются их фактические значения. Одним из примеров является универсальный массив регистров , где ширина массива задается через параметр. Такой массив в сочетании с общим проводным вектором может создать универсальный буфер или модуль памяти с произвольной разрядностью из реализации одного модуля. [32]

VHDL , являющийся производным от Ada, также имеет общие возможности. [33]

C поддерживает «обобщенные выражения типов», используя _Generic ключевое слово: [34]

#define cbrt(x) _Generic((x), long double: cbrtl, \ 
 default: cbrt, \ 
 float: cbrtf)(x) 

См. также [ править ]

Ссылки [ править ]

  1. ^ Ли, Кент Д. (15 декабря 2008 г.). Языки программирования: активный подход к обучению . Springer Science & Business Media. стр. 9–10. ISBN  978-0-387-79422-8 .
  2. ^ Милнер, Р.; Моррис, Л.; Ньюи, М. (1975). «Логика вычислимых функций рефлексивных и полиморфных типов». Материалы конференции по проверке и совершенствованию программ .
  3. ^ Гамма, Эрих; Хелм, Ричард; Джонсон, Ральф; Влиссидес, Джон (1994). Шаблоны проектирования . Аддисон-Уэсли. ISBN  0-201-63361-2 .
  4. ^ Musser & Stepanov 1989 .
  5. ^ Массер, Дэвид Р.; Степанов, Александр А. Универсальное программирование (PDF) .
  6. ^ Александр Степанов; Пол МакДжонс (19 июня 2009 г.). Элементы программирования . Аддисон-Уэсли Профессионал. ISBN  978-0-321-63537-2 .
  7. ^ Массер, Дэвид Р.; Степанов, Александр А. (1987). «Библиотека универсальных алгоритмов в Ada». Материалы ежегодной международной конференции ACM SIGAda 1987 года по Ada-SIGAda '87 . стр. 216–225. CiteSeerX   10.1.1.588.7431 . дои : 10.1145/317500.317529 . ISBN  0897912438 . S2CID   795406 .
  8. ^ Александр Степанов и Мэн Ли: Библиотека стандартных шаблонов. Технический отчет лабораторий HP 95-11(R.1), 14 ноября 1995 г.
  9. ^ Мэтью Х. Остерн: Общее программирование и STL: использование и расширение стандартной библиотеки шаблонов C++. Addison-Wesley Longman Publishing Co., Inc. Бостон, Массачусетс, США, 1998 г.
  10. ^ Джереми Г. Сик, Ли-Куан Ли, Эндрю Ламсдейн: Библиотека графиков повышения: Руководство пользователя и справочное руководство. Аддисон-Уэсли 2001 г.
  11. ^ Степанов, Александр. Краткая история STL (PDF) .
  12. ^ Перейти обратно: а б Страуструп, Бьерн. Развитие языка в реальном мире и для него: C++ 1991–2006 (PDF) . дои : 10.1145/1238844.1238848 . S2CID   7518369 .
  13. ^ Ло Руссо, Грациано. «Интервью с А. Степановым» .
  14. ^ Бэкхаус, Роланд; Янссон, Патрик; Журинг, Йохан; Меертенс, Ламберт (1999). Общее программирование – введение (PDF) .
  15. ^ Ламмель, Ральф; Пейтон Джонс, Саймон (январь 2003 г.). «Откажитесь от шаблона: практический шаблон проектирования для общего программирования» (PDF) . Майкрософт . Проверено 16 октября 2016 г.
  16. ^ Дос Рейс, Габриэль; Джарви, Яакко (2005). «Что такое общее программирование? (препринт LCSD'05)» (PDF) . Архивировано из оригинала (PDF) 25 декабря 2005 года.
  17. ^ Р. Гарсия; Дж. Джарви; А. Ламсдейн; Дж. Сик; Дж. Уиллкок (2005). «Расширенное сравнительное исследование языковой поддержки универсального программирования (препринт)». CiteSeerX   10.1.1.110.122 .
  18. ^ «Общие единицы» . www.adaic.org . Проверено 25 апреля 2024 г.
  19. ^ Страуструп, Дос Рейс (2003): Концепции - варианты дизайна для проверки аргументов шаблона
  20. ^ Страуструп, Бьярн (1994). «15.5 Как избежать репликации кода». Проектирование и эволюция C++ . Ридинг, Массачусетс: Аддисон-Уэсли. стр. 346–348. Бибкод : 1994декабрь..книга.....S . ISBN  978-81-317-1608-3 .
  21. ^ Ярко, Уолтер. «Типы Волдеморта в D» . Доктор Доббс . Проверено 3 июня 2015 г.
  22. ^ Создание объектно-ориентированного программного обеспечения, Prentice Hall, 1988, и объектно-ориентированное создание программного обеспечения, второе издание, Prentice Hall, 1997.
  23. ^ Эйфелева: Язык, Прентис Холл, 1991.
  24. ^ Блох 2018 , с. 126, §Пункт 28: Предпочитайте списки массивам.
  25. ^ История обобщений .NET/C#: некоторые фотографии за февраль 1999 г.
  26. ^ Альбахари 2022 .
  27. ^ C#: вчера, сегодня и завтра: интервью с Андерсом Хейлсбергом
  28. ^ Универсальные шаблоны в C#, Java и C++.
  29. ^ Анализ кода CA1006: не вкладывать универсальные типы в сигнатуры членов.
  30. ^ Ограничения на параметры типа (Руководство по программированию на C#)
  31. ^ Общее руководство пользователя Haskell.
  32. ^ Verilog на примере, раздел «Остальное для справки» . Блейн К. Ридлер, Full Arc Press, 2011. ISBN   978-0-9834973-0-1
  33. ^ https://www.ics.uci.edu/~jmoorkan/vhdlref/generics.html Справочник VHDL
  34. Проект комитета WG14 N1516 — 4 октября 2010 г.

Источники [ править ]

Дальнейшее чтение [ править ]

Внешние ссылки [ править ]

С++, Д
С#, .NET
Делфи, Объект Паскаль
Эйфелева
Хаскелл
Джава
Arc.Ask3.Ru: конец оригинального документа.
Arc.Ask3.Ru
Номер скриншота №: F0EC3E9BDC90DC5730B2CCCC6E1BA089__1714276080
URL1:https://en.wikipedia.org/wiki/Generic_programming
Заголовок, (Title) документа по адресу, URL1:
Generic programming - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть, любые претензии не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, денежную единицу можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)