Delphi 有没有一种干净的方法可以将匿名方法强制转换为指针?

Delphi 有没有一种干净的方法可以将匿名方法强制转换为指针?,delphi,delphi-xe7,Delphi,Delphi Xe7,我正在向外部函数传递一个匿名方法。匿名方法是一个被积函数,外部函数将计算一个定积分。因为集成函数是外部的,所以它不理解匿名方法。所以我必须以非类型指针的形式传递匿名方法。为了更清楚地说明这一点,它的运行方式如下: function ExternalIntegrand(data: Pointer; x: Double): Double; cdecl; begin Result := GetAnonMethod(data)(x); end; .... var Integrand: TFu

我正在向外部函数传递一个匿名方法。匿名方法是一个被积函数,外部函数将计算一个定积分。因为集成函数是外部的,所以它不理解匿名方法。所以我必须以非类型指针的形式传递匿名方法。为了更清楚地说明这一点,它的运行方式如下:

function ExternalIntegrand(data: Pointer; x: Double): Double; cdecl;
begin
  Result := GetAnonMethod(data)(x);
end;

....

var
  Integrand: TFunc<Double,Double>;
  Integral: Double;
....
Integral := CalcIntegral(ExternalIntegrand, CastToPointer(Integrand), xlow, xhigh);
编译器对象具有:

[dcc32错误]:E2035实际参数不足

显然,编译器正在尝试调用匿名方法

我能够做到这一点:

function CastToPointer(const F: TFunc<Double,Double>): Pointer; inline;
begin
  Move(F, Result, SizeOf(Result));
end;
函数CastToPointer(常量F:TFunc):指针;内联;
开始
移动(F,Result,SizeOf(Result));
结束;
或者这个:

function CastToPointer(const F: TFunc<Double,Double>): Pointer; inline;
var
  P: Pointer absolute F;
begin
  Result := P;
end;
函数CastToPointer(常量F:TFunc):指针;内联;
变量
P:指针绝对值F;
开始
结果:=P;
结束;
但我不能像在将动态数组转换为指向数组的指针时那样使用简单转换,这似乎有点让人恼火

我意识到我可以传递包含匿名方法的变量的地址。像这样:

function ExternalIntegrand(data: Pointer; x: Double): Double; cdecl;
var
  F: ^TFunc<Double,Double>;
begin
  F := data;
  Result := F^(x);
end;

....

Integral := CalcIntegral(ExternalIntegrand, @Integrand, xlow, xhigh);
函数ExternalIntegrand(数据:指针;x:Double):Double;cdecl;
变量
F:^TFunc;
开始
F:=数据;
结果:=F^(x);
结束;
....
积分:=预积分(外部积分,@被积函数,xlow,xhigh);
然而,引入另一个间接层次似乎有点奇怪


有人知道将匿名方法变量直接转换为指针的方法吗?我确实意识到这种诡计是值得怀疑的,但至少出于好奇,我想知道这是否可以做到

不确定这是否是您的意思,但如果您可以编写外部方法来接受非类型化参数,而不是
指针,则这是可行的

{$APPTYPE CONSOLE}

uses
  SysUtils;

function Foo(x : double) : double;
begin
  result := 4 * x;
end;

procedure Test2(const data);
begin
  WriteLn(TFunc<Double,Double>(data)(2));
end;

var
  F: TFunc<Double,Double>;
begin
  F := function(x : double) : double
       begin
         result := 2 * x;
       end;
  Test2(F);  // Anonymous method
  F := foo;
  Test2(F);  // Regular method
  ReadLn;
end.

您应该能够只执行
指针((@Integrand)^)
,因此您的调用将是:

Integral := CalcIntegral(ExternalIntegrand, Pointer((@Integrand)^), xlow, xhigh);
这是一种额外的间接层次,但不是:)

我通过与您的CastToPointer进行比较进行了测试,结果表明:

program Project8;

{$APPTYPE CONSOLE}

{$R *.res}

{$T+}

uses
  System.SysUtils;

  function CastToPointer(const F: TFunc<Double,Double>): Pointer; inline;
begin
  Move(F, Result, SizeOf(Result));
end;

var
  Integrand: TFunc<Double,Double>;
  Mypointer1: Pointer;
  Mypointer2: Pointer;
begin
  Integrand := function(x : double) : double
       begin
         result := 2 * x;
       end;
  Mypointer1 := Pointer((@Integrand)^);
  Mypointer2 := CastToPointer(Integrand);
  Assert(Mypointer1 = Mypointer2, 'Pointers don''t match!');
end.
程序项目8;
{$APPTYPE控制台}
{$R*.res}
{$T+}
使用
System.SysUtils;
函数CastToPointer(常数F:TFunc):指针;内联;
开始
移动(F,Result,SizeOf(Result));
结束;
变量
被积函数:TFunc;
Mypointer1:指针;
Mypointer2:指针;
开始
被积函数:=函数(x:double):double
开始
结果:=2*x;
结束;
Mypointer1:=指针((@Integrand)^);
Mypointer2:=CastToPointer(被积函数);
断言(Mypointer1=Mypointer2,'指针不匹配!');
结束。

@J。。。在实际arg中起作用的是一个非方法变量,但如果它是一个方法或函数,则不是。如果您打算将匿名函数和常规函数同时传递给
ExternalIntegrand
,那么
GetAnonMethod
看起来像什么?当然你需要知道它的类型。。。常规方法指针不会强制转换到
TFunc
——它不需要强制转换到某个
TFoo=function(x:double):double?@J。。。我想你是对的。调用
CalcIntegral
的函数接收一个anon方法作为参数,因此我在这一点上确定了类型。所以,我没有仔细考虑。我们当然可以为CastToPointer添加一个非类型化的指针版本,但它同样冗长。或者,如果您确实确定只传递匿名方法,那么我认为我的答案可以工作,而不需要额外的方法来执行强制转换(即:接受一个非类型化的参数,而不是一个
指针
)。。。我知道。那是我在抱怨一个似乎和我一样沮丧的人如果传递的是函数而不是匿名方法,那么它就不起作用。定义模块级函数并重试。更重要的是,这里没有指针。我正在调用一个接受
指针的函数。我确实需要它。@DavidHeffernan那么,假设您不控制外部方法的源代码是正确的吗(即:它必须接受显式
指针
类型)?另外,问题是关于匿名方法的——答案是否也应该涉及模块级函数?我实际上控制着这一切。但是如果我使用了一个非类型化的参数,那么我不能传递一个方法或函数,我必须传递一个anon方法。因为它们传递给非类型参数的方式不同。试试看。@DavidHeffernan啊,我明白了-解决方案还必须支持常规方法,而不仅仅是匿名方法。它们毕竟与匿名方法是赋值兼容的。在我的问题中,我几乎有一个非类型指针变体
CastToPointer
,但随后我碰到了那个绊脚石并将其移除。也许这一切告诉我的是,我应该使用
@F
,其中
F
是一个类型为anon方法的变量。
Integral := CalcIntegral(ExternalIntegrand, Pointer((@Integrand)^), xlow, xhigh);
program Project8;

{$APPTYPE CONSOLE}

{$R *.res}

{$T+}

uses
  System.SysUtils;

  function CastToPointer(const F: TFunc<Double,Double>): Pointer; inline;
begin
  Move(F, Result, SizeOf(Result));
end;

var
  Integrand: TFunc<Double,Double>;
  Mypointer1: Pointer;
  Mypointer2: Pointer;
begin
  Integrand := function(x : double) : double
       begin
         result := 2 * x;
       end;
  Mypointer1 := Pointer((@Integrand)^);
  Mypointer2 := CastToPointer(Integrand);
  Assert(Mypointer1 = Mypointer2, 'Pointers don''t match!');
end.