Справочник по Ada 2012
12.3 Обобщенное подстановление
Экземпляр обобщенного блока объявляется с помощью обобщенного_подстановления.
Синтаксис
обобщенное_подстановление ::=
package имя_определяющего_блока_программы is
new обобщенное_пакет_имя [часть_фактических_обобщенных_параметров]
[указание_аспекта];
| [индикатор_переопределения]
procedure имя_определяющего_блока_программы is
new обобщенная_процедура_имя [часть_фактических_обобщенных_параметров]
[указание_аспекта];
| [индикатор_переопределения]
function определяющий_идентификатор is
new обобщенная_функция_имя [часть_фактических_обобщенных_параметров]
[указание_аспекта];
package имя_определяющего_блока_программы is
new обобщенное_пакет_имя [часть_фактических_обобщенных_параметров]
[указание_аспекта];
| [индикатор_переопределения]
procedure имя_определяющего_блока_программы is
new обобщенная_процедура_имя [часть_фактических_обобщенных_параметров]
[указание_аспекта];
| [индикатор_переопределения]
function определяющий_идентификатор is
new обобщенная_функция_имя [часть_фактических_обобщенных_параметров]
[указание_аспекта];
обобщенное_сопоставление ::=
[обобщенное_формальный_параметр_имя_селектора =>] явный_фактический_обобщенный_параметр
[обобщенное_формальный_параметр_имя_селектора =>] явный_фактический_обобщенный_параметр
явный_фактический_обобщенный_параметр ::= выражение | переменная_имя
| подпрограмма_имя | вход_имя | метка_типа
| экземпляр_пакета_имя
| подпрограмма_имя | вход_имя | метка_типа
| экземпляр_пакета_имя
Обобщенное сопоставление является именованным или позиционным в зависимости от того, указано ли обобщенное_формальный_параметр_имя_селектора. Любые позиционные сопоставления должны предшествовать любым именованным сопоставлениям.
Фактический обобщенный параметр — это либо явный_фактический_обобщенный_параметр, указанный в обобщенном_сопоставлении для каждого формального параметра, либо соответствующее выражение_по_умолчанию или имя_по_умолчанию, если для формального параметра не указано обобщенное_сопоставление. Когда смысл ясен из контекста, термин «фактический обобщенный», или просто «фактический», используется как синоним «фактического обобщенного параметра», а также для представления, обозначаемого одним из них, или значения одного из них.
Правила легальности
В обобщенном_подстановлении для конкретного вида блока программы (пакет, процедура или функция), имя должно обозначать обобщенный блок соответствующего типа (обобщенный пакет, обобщенная процедура или обобщенная функция, соответственно).
Обобщенный_формальный_параметр_имя_селектора именованного обобщенного_сопоставления должен обозначать объявление_формального_обобщенного_параметра обобщенного блока, который подставляется. Если две или более формальных подпрограмм имеют одинаковое имя, то именованные сопоставления не допускаются для соответствующих фактических значений.
Объявление объявление_формального_обобщенного_параметра для позиционного обобщенного_сопоставления — это параметр с соответствующей позицией в части_формальных_обобщенных_параметров обобщенного блока, который подставляется.
Обобщенное подстановление должно содержать не более одного обобщенного_сопоставления для каждого формального параметра. Каждый формальный параметр без сопоставления должен иметь выражение_по_умолчанию или подпрограмма_по_умолчанию.
В обобщенном блоке Правила легальности применяются во время компиляции объявления_обобщенного_блока и тела обобщенного блока, учитывая свойства формальных параметров. В видимой части и части формальных параметров экземпляра, Правила легальности применяются во время компиляции обобщенного_подстановления, учитывая свойства фактических параметров. В других частях экземпляра Правила легальности не применяются; это правило не применяется, когда данное правило явно указывает иначе.
Статическая семантика
Обобщенное подстановление объявляет экземпляр; он эквивалентен объявлению экземпляра (объявление пакета или подпрограммы) непосредственно после тела экземпляра, в месте подстановки.
Экземпляр является копией текста шаблона. Каждое использование формального параметра превращается (в копии) в использование фактического значения, как объяснено ниже. Экземпляр обобщенного пакета — пакет, обобщенной процедуры — процедура, а обобщенной функции — функция.
Интерпретация каждого конструкта в обобщенном объявлении или теле определяется с использованием правил перегрузки при компиляции этого обобщенного объявления или тела. В экземпляре интерпретация каждого (скопированного) конструкта та же, за исключением случая имени, которое обозначает объявление_обобщенного_блока или некоторое объявление внутри обобщенного блока; соответствующее имя в экземпляре затем обозначает соответствующую копию обозначаемого объявления. Правила перегрузки не применяются в экземпляре.
В экземпляре объявление_формального_обобщенного_параметра объявляет представление, свойства которого идентичны свойствам фактического значения, за исключением того, что указано в 12.4, «Формальные объекты» и 12.6, «Формальные подпрограммы». Аналогично, для объявления в объявление_формального_обобщенного_параметра, соответствующее объявление в экземпляре объявляет представление, свойства которого идентичны соответствующему объявлению внутри объявления фактического значения.
Неявные объявления также копируются, и имя, обозначающее неявное объявление в обобщенном блоке, обозначает соответствующую копию в экземпляре. Однако для типа, объявленного в видимой части обобщенного блока, для использования за пределами экземпляра неявно объявляется весь новый набор примитивных подпрограмм, и он может отличаться от скопированного набора, если свойства типа каким-либо образом зависят от свойств указанного в подстановке фактического типа. Например, если тип в обобщенном блоке получен из формального частного типа, то в экземпляре тип унаследует подпрограммы от соответствующего фактического типа.
Эти новые неявные объявления появляются непосредственно после объявления типа в экземпляре и переопределяют скопированные. Скопированные могут вызываться только изнутри экземпляра; новые — только извне экземпляра, хотя для помеченных типов тело нового может выполняться вызовом старого.
В видимой части экземпляра явное объявление переопределяет неявное объявление, если они являются омографами, как описано в 8.3. С другой стороны, явное объявление в частной части экземпляра переопределяет неявное объявление в экземпляре только в том случае, если соответствующее явное объявление в обобщенном блоке переопределяет соответствующее неявное объявление в обобщенном блоке. Соответствующие правила применяются к другим видам переопределения, описанным в 8.3.
Правила после компиляции
Рекурсивное обобщенное подстановление не допускается в следующем смысле: если данный обобщенный блок включает подстановку второго обобщенного блока, то экземпляр, сгенерированный этой подстановкой, не должен включать экземпляр первого обобщенного блока (независимо от того, сгенерирован ли этот экземпляр непосредственно или косвенно промежуточными подстановками).
Динамическая семантика
Для разработки generic_instantiation каждый generic_association сначала оценивается. Если используется значение по умолчанию, для этого правила предполагается неявное generic_association. Эти оценки выполняются в произвольном порядке, за исключением случаев, когда оценка фактического значения по умолчанию происходит после оценки другого фактического значения, если значение по умолчанию включает name, обозначающее другое. Наконец, происходит разработка объявления экземпляра и тела.
Для оценки generic_association оценивается фактический параметр обобщенного типа. Дополнительные действия выполняются в случае формального объекта с режимом in (см. 12.4).
ПРИМЕЧАНИЯ
5 Если формальный тип не помечен, то тип обрабатывается как тип без метки внутри тела обобщенного типа. Наследование от такого типа в теле обобщенного типа разрешено; новый тип не получает новое значение метки, даже если фактическое значение помечено. Переопределенные операции для такого производного типа не могут быть вызваны извне экземпляра.
Примеры
Примеры обобщенных экземпляров (см. 12.1):
procedure Swap is new Exchange(Elem => Integer);
procedure Swap is new Exchange(Character); -- Swap перегружен
function Square is new Squaring(Integer); -- "*" для Integer используется по умолчанию
function Square is new Squaring(Item => Matrix, "*" => Matrix_Product);
function Square is new Squaring(Matrix, Matrix_Product); -- то же, что и предыдущее
procedure Swap is new Exchange(Character); -- Swap перегружен
function Square is new Squaring(Integer); -- "*" для Integer используется по умолчанию
function Square is new Squaring(Item => Matrix, "*" => Matrix_Product);
function Square is new Squaring(Matrix, Matrix_Product); -- то же, что и предыдущее
package Int_Vectors is new On_Vectors(Integer, Table, "+");
Примеры использования экземпляризованных единиц:
Swap(A, B);
A := Square(A);
A := Square(A);
T : Table(1 .. 5) := (10, 20, 30, 40, 50);
N : Integer := Int_Vectors.Sigma(T); -- 150 (см. 12.2, «Обобщенные тела» для тела Sigma)
N : Integer := Int_Vectors.Sigma(T); -- 150 (см. 12.2, «Обобщенные тела» для тела Sigma)
use Int_Vectors;
M : Integer := Sigma(T); -- 150
M : Integer := Sigma(T); -- 150