Просто обнаруженный что-то довольно забавное:
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));
Существует ли более изящное решение?
Здесь есть небольшая синтаксическая двусмысленность относительно того, относится ли имя «Dequeue» к самой функции или к ее возвращаемому значению. И поскольку вы имеете дело с указателем анонимного метода, которому вы можете назначить обычную функцию, он пытается интерпретировать это как назначение функции, а не назначение результата функции. Приведение его к указателю - неправильное решение, так как это заставит выполнить назначение функции, что затем вызовет всевозможные забавные ошибки при попытке вызвать MyProc.
Правильный способ исправить это - устранить синтаксическую двусмысленность. Поставьте пустую скобку после Dequeue, чтобы компилятор был уверен, что вы вызываете функцию, а не просто ссылаетесь на нее по имени, и тогда она будет работать.
MyProc := Queue.Dequeue();
Как сказал Мейсон, синтаксис 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