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