Получите TProc от универсального контейнера

Просто обнаруженный что-то довольно забавное:

var
  Queue  : TQueue <TProc>;
  MyProc : TProc;
...
MyProc := Queue.Dequeue;

Я думаю, что Вы видите то, что является intendend здесь. Однако компилятор думает, что я хочу сохранить Queue.Dequeue метод (вводят "процедуру объекта") в MyProc и сообщает об ошибке

E2010 Incompatible Types: 'TProc' und 'Procedure of object'

Обходное решение, которое я придумал, идет как это

MyProc := TProc (Pointer (Queue.Dequeue));

Существует ли более изящное решение?

7
задан jpfollenius 17 February 2010 в 13:58
поделиться

2 ответа

Здесь есть небольшая синтаксическая двусмысленность относительно того, относится ли имя «Dequeue» к самой функции или к ее возвращаемому значению. И поскольку вы имеете дело с указателем анонимного метода, которому вы можете назначить обычную функцию, он пытается интерпретировать это как назначение функции, а не назначение результата функции. Приведение его к указателю - неправильное решение, так как это заставит выполнить назначение функции, что затем вызовет всевозможные забавные ошибки при попытке вызвать MyProc.

Правильный способ исправить это - устранить синтаксическую двусмысленность. Поставьте пустую скобку после Dequeue, чтобы компилятор был уверен, что вы вызываете функцию, а не просто ссылаетесь на нее по имени, и тогда она будет работать.

MyProc := Queue.Dequeue();
11
ответ дан 6 December 2019 в 11:48
поделиться

Как сказал Мейсон, синтаксис Delphi неоднозначен. Если TFoo.Bar - это метод, неясно, что FooValue.Bar означает ссылку на результат вызова TFoo.Bar или указатель метода ( или ссылка) TFoo.Bar (с подразумеваемым аргументом Self для FooValue).

В комментариях к ответу Мейсона Роб Кеннеди, кажется, предлагает компилятору просто вычислить это, основываясь на типах всего задействованного. Это не просто; компилятор уже проделал большую работу, чтобы выяснить, имеете ли вы в виду ссылку на значение указателя метода или вызов метода. Фактически он анализирует выражения по-другому, когда ожидаемый получатель является типом указателя метода (или ссылки, или указателя функции). Усилия особенно необходимы, когда перегрузки представлены в изображении: компилятор просматривает каждого кандидата на перегрузку и проверяет типы указателей метода в каждой позиции параметра, а затем анализирует аргументы по-разному в зависимости от того, содержит ли эта позиция параметра указатель функции в одном перегрузок. Затем, если перегрузка, ожидающая указателя функции , не соответствует , компилятор изменяет дерево синтаксического анализа с указателя функции на вызов метода. Сам механизм перегрузки должен выяснить, что использовать при сравнении значений параметров. Это довольно беспорядочно, и было бы здорово, если бы мы не усложняли его.

Операторы в стиле префикса, такие как @ или Addr () , не очень помогают в разрешении этой неоднозначности, не в последнюю очередь потому, что функции могут возвращать указатели на функции и так далее; сколько @ вам нужно, чтобы запретить неявный (не требуется () ) вызов, чтобы получить правильное значение? Поэтому, когда были введены анонимные методы, было внесено изменение в синтаксический анализ выражений: я представил возможность использования () для принудительного вызова.

Подробнее об этом можно прочитать здесь:

http://blog.barrkel.com/2008/03/odd-corner-of-delphi-procedural.html

и здесь:

http: //blog.barrkel.com/2008/03/procedurally-typed-expressions-redux.html

6
ответ дан 6 December 2019 в 11:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: