лекции (2015) (1160856), страница 13
Текст из файла (страница 13)
Его именем является идентификаторшаблона. Идентификатор шаблона полностью эквивалентен имени типа. При порождении новоготипа может происходить генерация кода для функций — членов нового типа.Порожденные функции можно рассматривать как семейство перегруженных функций (считая, чтоимя порожденной функции совпадает с именем шаблона функции). Тогда возникает возможностьвызова порожденной функции без явного указания параметров шаблона. Поскольку компиляторзнает профиль вызова (например, (int)), то он может сопоставить его с профилем шаблоннойфункции ( (Т)) и отождествить (int<->T).
Это процесс называется выводом типа.Важно понимать, что для конкретизации необходимо иметь полный текст шаблона (как функции, таки класса, включая определения всех его членов). Порождение новой сущности происходит во времяконкретизации с учетом контекста конкретизации и полного текста шаблона.
Именно поэтомубиблиотеки шаблонов распространяются в исходных текстах (иначе их использовать нельзя).Доступность полной информации как о шаблоне, так и о контексте конкретизации позволяетреализовать такие понятия, как перегрузка шаблонов функций, явная специализация шаблонов ичастичная специализация шаблонов классов.68Явная специализацияЯвная специализация шаблона порождает вариант шаблона для конкретного набора егоаргументов.
Явную специализацию иногда путают с конкретизацией, ведь и при конкретизации тожеуказываются аргументы. Конкретизация указывает компилятору следующее: возьми шаблон,примени к нему аргументы и породи новый класс (функцию), а явная специализация — это указаниевзять новое описание старого шаблона, набор аргументов и считать, что это новый шаблон, которыйприменим только к этому набору и порождает только один вариант.вариант.Явная специализация шаблона функции —это конкретная функция с именемшаблонной функции, перед объявлениемкоторой стоит template <>При явной специализации функций template<> можно опускать, тогда специализациябудет иметь вид обычной функции. Дляклассов template<> опускать нельзя.Когда компилятор видит вызов функции сименем шаблона, то он пытается сначаланайти явную специализацию, и только еслиее нет, ищет шаблон.// некоторая шаблонная функцияtemplate<class T> void f(T t) {};// явная специализация 1template<> void f<char>(char c) {}// явная специализация 2template<> void f(double d) {}template <typename Т> classContainer {// реализация} ;template <> class Container<constchar *> {// оптимизированная реализация} ;Частичная специализацияЧастичная специализация порождает новый вариант параметризованного шаблона, которыйявляется частным случаем общего шаблона.
Набор аргументов, подходящих для частичнойспециализации, подходит и для общего шаблона, но является «более точным».Например, общий шаблон использует просто имя любого типа, а частичная специализация — типуказателя, тип массива, функциональный тип и т. п. Другим вариантом специализации являетсяменьшее число параметров, чем в общем случае, и т.д.Пример:template<class T1, class T2, int I>class A {}; // общий шаблон// частичная специализация, где T2 - указатель на T1template<class T, int I>class A<T, T*, I> {};// частичная специализация, где T1 - указательtemplate<class T, class T2, int I>69class A<T*, T2, I> {};// частичная специализация, где T1 - int, I - число 5, T2 - указательtemplate<class T>class A<int, T*, 5> {};Обобщения в C#. Ключевое слово whereНа уровне синтаксиса универсальные шаблоны языка C# являются более простым подходом (посравнению с C++) к параметризованным типам, исключающим сложность шаблонов языка C++.Кроме того, в языке C# не делается попытки обеспечить все функциональные возможности,обеспечиваемые шаблонами языка C++.На уровне реализации основное отличие заключается втом, что замена универсальных типов языка C# выполняется во время выполнения иинформация универсальных типов, таким образом, сохраняется для экземпляров объектов.Обобщения C# не поддерживают ни явной, ни частичной специализации, не позволяет параметрамтипов иметь значения по умолчанию.При определении универсального типа можно ограничить виды типов, которые могутиспользоваться клиентским кодом в качестве аргументов типа при инициализациисоответствующего класса.
При попытке клиентского кода создать экземпляр класса с помощью типа,который не допускается ограничением, в результате возникает ошибка компиляции.Это называетсяограничениями. Ограничения определяются с помощью контекстно-зависимого ключевого словаwhere.В следующей таблице приведены шесть типов ограничений:where T: structАргумент типа должен иметь тип значения.where T : classАргумент типа должен иметь ссылочный тип;это также распространяется на тип любогокласса, интерфейса, делегата или массива.where T : new()Аргумент типа должен иметь открытыйконструктор без параметров.
Прииспользовании с другими ограничениямиограничение new() должно устанавливатьсяпоследним.where T : <base class name>Аргумент типа должен являться или бытьпроизводным от указанного базового класса.where T : <interface name>Аргумент типа должен являться илиреализовывать указанный интерфейс.Можно установить несколько ограниченийинтерфейса.Ограничивающий интерфейстакже может быть универсальным.where T : UАргумент типа, предоставляемый в качествеT, должен совпадать с аргументом,предоставляемым в качестве U, или бытьпроизводным от него.// Общий шаблонpublic class GenericList1<T> {void Add(T input) { }}70// Общий шаблон с ограничениямиpublic class GenericList2<T> where T : class, new() {void Add(T input) { }}class TestGenericList {private class ExampleClass { }static void Main() {// Declare a list of type int.GenericList<int> list1 = new GenericList1<int>();// Declare a list of type string.GenericList<string> list2 = new GenericList1<string>();}}Обобщения в Java.
Ограничения с помощью extends, super и wildcardsОбобщения в Java по своей природе аналогичны обощениям в C#. Синтаксис определенияшаблонных методов и классов является фактически одинаковым за исключением синтаксисаограничений.●●●<T extends X> - тип T должен либо совпадать с X, либо являтся производным от негоклассом.<T super X> - тип T должен либо совпадать с X, либо являтся одним из его суперклассов(предков).
Можно использовать данное ограничение только с шаблонными методами, но не склассами.<? extends X>, <? super X> - если в теле шаблонного класса или функции нам не нужноработать непосредственно с подставляемым типом, то можно использовать wildcardнотацию.Пример:public class Garage<X extends Vehicle> { }class Car extends Vehicle { }class Motorcycle extends Vehicle { }class Fruit extends Object { }class Vehicle { }interface PassengerVehicle { }interface MotorVehicle { }class ParkingGarage<X extends Vehicle & MotorVehicle & PassengerVehicle>int totalFuel(List<? extends Vehicle> list) {int total = 0;for(Vehicle v : list) {total += v.getFuel();}return total;}71Шаблоны в Ада-83В Аде используется понятие дженериков (generic units).
По своей природе они очень близки кшаблонам C++.В Ада объявление шаблонной функции просходит в два действия: объявления дженерика иобъявление самой функции.Примеры:Обмен двух чиселКаркас шаблонного стекаgenerictype Element_T is private;procedure Swap (X, Y : in outElement_T);genericMax: Positive;type Element_T is private;package Generic_Stack isprocedure Push (E: Element_T);function Pop return Element_T;end Generic_Stack;procedure Swap (X, Y : in outElement_T) isTemporary : constant Element_T := X;beginX := Y;Y := Temporary;end Swap;package body Generic_Stack isStack: array (1 ..
Max) ofElement_T;Top : Integer range 0 .. Max := 0;-- ...end Generic_Stack;72.