ГОСТ Р 56271-2014
Приложение Е
(справочное)
Рекурсивное и нерекурсивное расширение шаблона
Е.1 Номенклатура
На компьютерном языке слова макрос, шаблон, встраивание (замещение вызова) используются для обо
значения различных частично перекрывающихся понятий.
Макрос:
- на языке LISP макрос — функция, выполняемая впроцессе компиляции. Она формирует вспомогательную
программу, которая встраивается в нужное место. Так как данная функция работает в произвольном коде, это
весьма общий механизм:
- в препроцессоре языка С (срр) вызов макроса заменяется тестом на расширение. После этого снова про
изводится сканирование для поиска вызовов макроса. Обычно препятствий для рекурсии нет, однако это приводит к
зацикливанию препроцессора. Блок GNU
3
(срр) может выявлять и блокировать рекурсию;
- в языке ТеХ, макросы расширяются аналогично (срр). рекурсия допускается. Но здесь также используются
условные структуры данных, позволяющие предотвращать рекурсию.
Шаблон:
- вязыке C++ шаблоны, изначально рассматривавшиеся как средства описания параметрического полимор
физма типов данных, также могут быть рекурсивными. Допускаются несколько расширений одного шаблона с раз
личными аргументами. Компилятор предпочитает самое конкретное определение, соответствующее конкретной
реализации. Это дает возможность определить завершающий «базовый случай». Данная ситуация часто имеет
место при так называемом мета-программировании шаблона;
- шаблоны кодов в средах IDE4.
Встраивание (замещение вызова): вычислительный процесс, где вызовы функции/процедуры не компили
руются в код, который сначала использует стековую память, чтобы запомнить свое предыдущее состояние, а затем
«прыгает» вкодфункции. Вместо этого телофункции расширяется вместе вызова. Данный процесс не откликается
на рекурсивные вызовы или. по крайней мере, ограничивает глубину замещаемого вызова. Некоторые компиля
торы производят так называемое встраивание «за кулисами». В языке GNU функцию можно также объявить как
встраивание, чтобы подсказать компилятору порядок действий. В отличие от ограничений на рекурсию, семантика
функции замещения вызова похожа на семантику нормальной функции, но код работает быстрее.
Так как настоящий стандарт определяет работу с шаблонами, то мы далее будем говорить о механизмах
работы шаблонов при обсуждении различных вариантов их определения.
Е.2 Использовать рекурсию или нет?
2
Имеет место существенная разница между шаблонами и макро-механизмами, допускающими циклические
(рекурсивные) определения и не допускающими их.
Обсуждение данного вопроса см. в 1.3.1 и 2.2.2 [11]. Различие между рекурсивными и нерекурсивными ма
кросами то же самое, что различив между циклическими и ациклическими элементами ТВох.
Пример надлежащего определения одного нерекурсивного механизма расширения макроса приведен в [16].
Рассмотрим абстрактное описание множества определений шаблона. Пусть N — это множество возможных
имен шаблонов или других частей языка. Пусть определение шаблона дает определение некоторого имени neN.
ссылающегося на (или использующее) имена различных других шаблонов или других элементов с именами N.
например, л,. л .....г\ .... Пусть л > п,. если на л, имеется ссылка в определении л. Например, для определения
шаблона:
SpecOrEqual(a,b):=Spec(a.b)va = b(1)
имеем SpecOrEqual >Spec, тогда как для определения:
SpecStar(a.b):=(3x.Spec(a,x)ASpecStar(x,b))va =b(2)
получаем SpecStar >Spec и SpecStar >SpecStar. Если имеются несколько таких определений, то пусть знак «>»
— это объединение всех зависимостей, данных определениями индивидуальных обьектов.
Для нерекурсивных механизмов шаблонов, зависимость «>» для всех определений должна быть
ациклической. Тоесть не должно существовать последовательности л
0
>л, > ... > пк. где л
0
= пк. В частности, не
существует такое л0, для которого л
0
> л0.
_____Другими словами, транзитивное замыкание
>4
должно быть нерефлексивным.
3
GNU — это рекурсивный акроним «GNUs Not Unix».
4
Интегрированная среда разработки.
79