> -- Цитата:
> PROCEDURE Список(Элемент1 ... ЭлементЭн);[...]В С++ это делается шаблонами, которые зачастую получаются ещё ужаснее, чем динамика.
Вместо "variadic templates" со всякими "unpacking" можно применить дженерики, есс-но если таковы существуют, вместе с адекватной системой типизации. Выше была ссылка на "макросы", там рядом предлагались и дженерики, но упрощённые и без статической типизации.

А так, к примеру, в некоторых ML-вариациях поступают примерно так:
## Код:
```
fun tuple_str[U, V](x: U * V) =>
      match x with
      | a , b => str a +", " + str b
      end;

fun tuple_str[U, V](x: U ** V) =>
      match x with
      | a ,, b => str a +", " + tuple_str b
      end;

...
// применение:
a = tuple_str(12, 345.5444, "str1");
```

Тип вида "U * V" (через лог. and) есть обычный кортеж (из 2-х элементов типа U и V). Тип "U ** V" (U в степени V) есть обобщённая структура: элементы в количестве V произвольного типа U (по аналогии представления массивов вида "int ^ 3"). Оператор ",," разрезает кортеж на "голову" и "хвост" (в стиле оператора "::" для списков), хвост не используется ни для чего, кроме "нарезки" при сопоставлении и для передачи аргумента функции. На месте рекурсивного вызова возникает "инстанцирование шаблона" (рекурсивно). Такие функции должны иметь соответствующий "pattern matching" на самом верхнем уровне (который может быть выражен по-разному). И есс-но действуют необходимые (очевидные) правила перегрузки функций.

Для Паскале-подобного языка можно попробовать аналогию, без дженериков, используя древние трюки в стиле Delphi.
Не в курсе (я не активный пользователь Оберонов), возможны ли такие выкрутасы, о которых далее, но пусть в качестве бреда, во всяком случае.