I want to create a procedure witch makes some manipulation with variable record type. Globally, I have a array of record. I want to sort the array, but by record’s field. I want to pass the field as procedure’s parameter. And the question is: how to pass field of record as parameter. For example: f2 – function, which returns field’s value and the field is offset.
type TCell = record
a: byte;
b: byte;
end;
function f2(cell: Tcell; offset: byte): byte;
begin
**result:=cell.offset**
end;
begin
c: TCell;
c.a:=10; c.b:=20;
writeln(f2(c, 2)) // 20;
end;
Is it possible for Delphi? it is certainly possible in Pascal via pointers, but the following doesn’t work in Delphi and compiler raises E2015 “Operator not applicable to this operand type” error.
function f1(a: pointer; offset: integer): byte;
begin
f1 := PByte(a+offset)^; //<--- error here
end;
begin
cell.a:=10; cell.b:=20;
writeln(f1(@cell,0));
writeln(f1(@cell,1));
end.
1
Well, let me first answer your “actual” question:
Globally, I have a array of record. I want to sort the array, but by record’s field.
In modern versions of Delphi, you use generics for this:
type
TCell = record
a, b: Byte
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
var Arr := TArray<TCell>(nil);
TArray.Sort<TCell>(
Arr,
TComparer<TCell>.Construct(
function(const Left, Right: TCell): Integer
begin
Result := Left.a - Right.a // no overflow risk
end
)
);
end;
I want to pass the field as procedure’s parameter.
Create an enumerated type for the various fields and use a case
statement.
You can also use RTTI, but that will not be as performant.
it is certainly possible in Pascal via pointers
You can use pointers in Delphi as well, but this is very rarely good practice unless you are a Delphi expert and really need the absolute best performance or most golfed code.
type
TCell = packed record
a, b: Byte
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
var Cell := Default(TCell);
Cell.a := 100;
Cell.b := 200;
var p := PByte(@Cell);
ShowMessage(p^.ToString);
ShowMessage((p + 1)^.ToString);
end;
The trick here is that PByte
is declared with pointer arithmetic on. Indeed, in System.pas
you’ll find
{$POINTERMATH ON}
PByte = ^Byte; {$NODEFINE PByte} { defined in sysmac.h }
{$POINTERMATH OFF}
You can always use this trick on your own pointer types.
Your code
f1 := PByte(a+offset)^; //<--- error here
doesn’t work because a
is a Pointer
and offset
an Integer
and you cannot +
a Pointer
and an Integer
.
But
PByte(PByte(a) + offset)^
would work.
5