Можно ли инициализировать постоянный массив ссылок на функции? - PullRequest
0 голосов
/ 27 июня 2018

После прочтения документации Embarcadero по процедурным типам & анонимным методам и объяснения Дэвида Хеффернана по этому вопросу, я до сих пор не совсем понимаю, почему компилятор запрещает инициализация константного массива ссылки на функцию, как C_BAR в приведенном ниже примере.

program MyProgram;

{$APPTYPE CONSOLE}

{$R *.res}

type
  TFoo = function: Integer;
  TBar = reference to function: Integer;

  function FooBar: Integer;
  begin
    Result := 42;
  end;

const
  // This works
  C_FOO: array[0..0] of TFoo = (FooBar);

  // These lines do not compile
  // C_BAR: array[0..0] of TBar = (FooBar); // TBar incompatible with Integer
  // C_BAR: array[0..0] of TBar = (@FooBar); // TBar incompatible with Pointer

var
  Foo: array[0..0] of TFoo;
  Bar: array[0..0] of TBar;
begin
  Foo[0] := FooBar; // Foo[0] = MyProgram.FooBar
  Bar[0] := FooBar; // Bar[0] = MyProgram$1$ActRec($1CC8CF0) as TBar

  Foo[0] := C_FOO[0]; // Foo[0] = MyProgram.FooBar
  Bar[0] := C_FOO[0]; // Bar[0] = MyProgram$1$ActRec($1CC8CF0) as TBar
end.

Используя отладчик, я вижу, что Bar [0] равен некоторому адресу (я думаю?), Который говорит мне, что что-то происходит за моим пониманием ...

Так можно ли инициализировать массив констант типа C_BAR в моем примере? Если да, как это сделать, а в противном случае, почему?

1 Ответ

0 голосов
/ 27 июня 2018

Соответствующая документация находится здесь в разделе Типизированные константы :

Типизированные константы, в отличие от истинных констант, могут содержать значения массива, типы записей, процедур и указателей. Типизированные константы не могут встречаться в константные выражения.

Объявите типизированную константу следующим образом:

const identifier: type = value

где идентификатор - любой допустимый идентификатор, тип - любой тип, кроме файлы и варианты, а значение является выражением типа. Например,

const Max: Integer = 100;

В большинстве случаев значение должно быть константным выражением; но если тип является массив, запись, процедурный тип или тип указателя, применяются специальные правила.

Эти специальные правила для процедурных типов следующие:

Чтобы объявить процедурную константу, укажите имя функции или Процедура, которая совместима с объявленным типом константы. Например,

function Calc(X, Y: Integer): Integer;
begin
  ...
end;
type TFunction = function(X, Y: Integer): Integer;
const MyFunction: TFunction = Calc;

С учетом этих деклараций вы можете использовать процедурную константу MyFunction в вызове функции:

I := MyFunction(5, 7)

Вы также можете присвоить значение nil процедурной константе.

Это объясняет, почему вы можете объявить типизированную константу с помощью TFoo.

Что касается анонимных методов, они нигде не перечислены в этой документации. Теперь анонимный метод реализован как интерфейс. Этот интерфейс имеет класс поддержки, сгенерированный компилятором, и поэтому должен быть создан экземпляр этого класса. Этот экземпляр размещается в куче, и это (по крайней мере, одна причина), почему вы не можете объявить анонимный метод константой.

...