нотация do волшебным образом исправляет в качестве аргумента выражение, которое в противном случае было бы отвергнуто

В шаблонах Nim: в качестве продолжения этой проблемы у меня возникла идея обойти недоступность аргумента по умолчанию с помощью используя перегрузку или даже в этом случае обычную упаковку. Хотя было бы слишком хорошо, если бы что-то снова не попало в вентилятор, позвольте мне поделиться:

Обратите внимание, что bodyFinally теперь является жестким (необходимо указать) аргументом.

template tpl(x: bool, body: untyped, bodyFinally: untyped): void =
  if x: body
  else: bodyFinally

# we add a convenience helper with 2 args here.
template tpl2(x: bool, body: untyped): void =
  tpl(x) do:
    body
  do:
    discard

#call site:
var r: int
tpl2(true) do:
  r = 2

круто (работает). Хотя это был не первый мой шанс на tpl2; это было:

template tpl2(x: bool, body: untyped): void =
  tpl(x, body, discard)

Потому что это то, что do предположительно переписывает. За исключением того, что мы получаем:

Ошибка: ожидалось выражение, но найдено "отбрасывание ключевого слова"

Так что же с этим?


person v.oddou    schedule 02.04.2018    source источник


Ответы (1)


Немного сложно объяснить, почему, но вы могли бы написать перегрузку следующим образом:

template tpl(x: bool, body: untyped, bodyFinally: untyped) =
  if x: body
  else: bodyFinally

template tpl(x: bool, body: untyped): void =
  tpl(x, body, (discard))

var r = 1

tpl(false):
  r = 2

echo r

tpl(true):
  r = 3

echo r

Дополнительные скобки запускают специальное правило синтаксического анализа, создающее узел nkStmtListExpr AST, который здесь является допустимым входом для шаблона. Эта конструкция обычно используется в операторах if в стиле C, которые включают присваивание, за которым следует проверка NULL:

if (let f = fopen(...); f != 0):
  # do something with `f`

Как и ожидалось, результат выполнения вышеуказанной программы будет таким:

1
3
person zah    schedule 02.04.2018