I'm passing an anonymous method to an external function. The anonymous method is an integrand and the external function will calculate a definite integral. Because the integration function is external it does not understand anonymous methods. So I'm having to pass the anonymous method as an untyped pointer. To make this clearer, it runs like this:
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);
Here CalcIntegral
is the external function that will call ExternalIntegrand
. That in turn takes the untyped pointer that is passed on, retrieves the anonymous method, and gets it to do that work.
The problem is that I can't write CastToPointer
cleanly. If I do:
Pointer(Integrand)
the compiler objects with:
[dcc32 Error]: E2035 Not enough actual parameters
Clearly the compiler is trying to call the anonymous method.
I am able to do this:
function CastToPointer(const F: TFunc<Double,Double>): Pointer; inline;
begin
Move(F, Result, SizeOf(Result));
end;
or this:
function CastToPointer(const F: TFunc<Double,Double>): Pointer; inline;
var
P: Pointer absolute F;
begin
Result := P;
end;
But it seems somewhat galling that I cannot use a simple cast as I might when casting a dynamic array to a pointer to the array.
I realise that I could pass the address of the variable holding the anonymous method. Like this:
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);
However, it seems a little odd to have to introduce another level of indirection.
Does anybody know a way to cast an anonymous method variable directly to a pointer? I do realise that such skullduggery is questionable but at least out of curiosity I'd like to know if it can be done.
You should be able to just do Pointer((@Integrand)^)
so your call would be:
Integral := CalcIntegral(ExternalIntegrand, Pointer((@Integrand)^), xlow, xhigh);
It's sort of an extra level of indirection but not :)
I tested by comparing to your CastToPointer and it works:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With