5

次のコード(問題を示すためだけに作成されたもの)は、Delphi 2010 でコンパイルおよび動作します。Delphi 2009 では、コンパイラは「E2035 実際のパラメータが不足しています」で失敗します。

program Project50;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TMyProc = reference to procedure(param: integer);

var
  a: TProc;
  b: TMyProc;

begin
  b := procedure (param: integer)
    begin
    end;
  a := TProc(b); // <-- [DCC Error] Project50.dpr(19): E2035 Not enough actual parameters
end.

この問題を回避するための非常に醜いハックを 1 つだけ見つけました (a: TProc absolute b)。このコンパイラの欠陥に対するより良い回避策を知っている人はいますか?

[TProc フィールドは実際には、さまざまな「実行可能」コード (TProcedure、TMethod、および TProc) を格納できるレコード内に隠されています。キャストは、特定の匿名プロシージャをこのフィールドに格納するために使用されます。]

4

3 に答える 3

2

コツはやらないこと

a := TProc(b);

しかし

TMyProc(a) := b;

これは、D2009 でコンパイルおよび動作します。以下にサンプルプロジェクトを添付します。

program Project51;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TMyProc = reference to procedure(var param: integer);

  TStorage = record
    FDelegate: TProc;
  end;

var
  a    : TMyProc;
  b    : TMyProc;
  param: integer;
  stg  : TStorage;

begin
  b := procedure (var param: integer)
    begin
      param := 2*param;
    end;
//  stg.FDelegate := TMyProc(b); // doesn't compile in Delphi 2009, compiles in Delphi 2010
  TMyProc(stg.FDelegate) := b;
  param := 21;
  TMyProc(stg.FDelegate)(param);
  Writeln(param);
  Readln;
end.

ただし、ローカル変数にキャストする場合、これは機能しません。

var
  p: TProc;
  a: TMyProc;

TMyProc(p) := a; // this will not compile

好奇心旺盛で好奇心旺盛。

于 2010-02-22T08:44:27.353 に答える
1

私はハック#2を見つけました:

program Project1;

{$APPTYPE CONSOLE}


uses
  SysUtils;

type
  TMyProc = reference to procedure(param: integer);

var
  a: TProc;
  b: TMyProc;

begin
  b := procedure (param: integer)
    begin
      Writeln('asdf');
    end;
  PPointer(@a)^ := PPointer(@b)^;
  a;
  readln;
end.

TMyProc(param引数あり)をTProc(引数なし)に割り当てることで何を達成しようとしているのか疑問です。


更新:ハック#3(refカウンターをインクリメントする必要があり、アイデアはSystem._IntfCopyから盗まれます):

procedure AnonCopy(var Dest; const Source);
var
  P: Pointer;

begin
  P:= Pointer(Dest);
  if Pointer(Source) <> nil
    then IInterface(Source)._AddRef;
  Pointer(Dest):= Pointer(Source);
  if P <> nil then
    IInterface(P)._Release;
end;

var
  a: TProc;
  b: TMyProc;

begin
  b := procedure (param: integer)
    begin
      Writeln('asdf');
    end;
  AnonCopy(a, b);
//  PPointer(@a)^ := PPointer(@b)^;
  a;
  readln;
end.
于 2010-02-21T23:08:11.570 に答える
1

最善の方法は、ジェネリックを使用して正しいタイプのデリゲートをレコードに格納することです。ハックは必要ありません。

program Project51;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TMyProc = reference to procedure(var param: integer);

  TStorage<T> = record
    FDelegate: T;
  end;

var
  a    : TMyProc;
  b    : TMyProc;
  p    : TProc;
  param: integer;
  stg  : TStorage<TMyProc>;

begin
  b := procedure (var param: integer)
    begin
      param := 2*param;
    end;
  stg.FDelegate := b;
  param := 21;
  stg.FDelegate(param);
  Writeln(param);
  Readln;
end.
于 2010-02-22T08:58:00.883 に答える