8.3 Специализация дженерика класса

На верх  Назад  Вперёд

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

Что может быть сделано в любом блоке Type  для определения типов. Специализированный тип выглядит следующим образом:


Специализация типа

802


Которое является очень простым определением. Учитывая объявление TList в предыдущем разделе, будет  действительно следующее определение типа:

Type

   TPointerList = specialize TList<Pointer>;

   TIntegerList = specialize TList<Integer>;

В версии 3.0 Free Pascal, в объявлении переменной, тоже может быть использовано ключевое слово specialize:

Var

   P : specialize TList<Pointer>;

Типы в операторе specialize, должны быть известны (на момент специализации), за исключением другого определения типа дженерика. Исходя из определения двух классов дженериков:

type

   Generic TMyFirstType<T1> = Class(TMyObject);

   Generic TMySecondType<T2> = Class(TMyOtherObject);

Недопустима следующая специализация:

type

   TMySpecialType = specialize TMySecondType<TMyFirstType>;

Так как тип TMyFirstType - это обобщенный тип, и он не полностью определен. Компилятор будет жаловаться:

Error: Generics cannot be used as parameters when specializing generics

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

Но разрешено следующее:

type

   TA = specialize TMyFirstType<Atype>;

   TB = specialize TMySecondType<TA>;

Потому что TA уже полностью определен, на момент специализации TB.

Тем не менее, ключевое слово specialize можно использовать при определении дженерика типов, как показано в приведенном примере:

generic TList<_T>=class(TObject, specialize IList<_T>)

и

generic TPointSet<t> = array of specialize PlanarCoordinate<t>;

В этих определениях дженерика специализация осуществляется только тогда, когда специализируется сам дженерик, и все типы становятся известны.

Замечание:

Начиная с версии 3.0, можно сделать определение дженерика классов заранее (forward definition). В предыдущих версиях компилятор генерировал ошибку, если предварительное объявление класса было позже чем специализация дженерика. Это значит, что теперь возможно следующее:

{$mode objfpc}

Type

  TMyClass = Class;

 

  // Другие объявления

 

  TMyClass = specialize TList<T>;