简体   繁体   中英

How can I declare a pointer based on a generic type?

I have a class like this:

type A = class
    procedure<T> DoStuff(tPtr: ^T);
end;

But when I try to compile, Delphi gives me this error:

[DCC Error] RPML.pas(57): E2029 Identifier expected but '^' found

How can I use a pointer to a parameterized type in a Delphi procedure? I don't want to make the whole class a template class.

To do this you need to declare a pointer type as a nested type in the generic class:

type 
  TMyGeneric<T> = class
  type
    P = ^T;
  public
    procedure DoStuff(tPtr: P);
  end;

And if you want a class method (ie not an instance method) you can do it this way:

type
  TMyGeneric<T> = record
  type
    P = ^T;
  public
    class procedure DoStuff(tPtr: P); static;
  end;

var
  int: Integer;
...
TMyGeneric<Integer>.DoStuff(@int);

Or using a var parameter:

type
  TMyGeneric<T> = record
  public
    class procedure DoStuff(var a: T); static;
  end;

It seems to be common to use records rather than classes for generic types that don't ever get instantiated.

Finally, you cannot have, in Delphi, a generic method without making the class generic. In other words there is no analogue of the following C++ template code:

Thorsten's answer shows how to implement a generic method without making the class generic, that is the Delphi analogue of of the following C++ template code:

class C {
public:
   template <typename T>
   int SomeTemplateFunction(T* data) {
      printf("Address of parameter is %p\n", data);
      return 0;
   }
};

int a; 
char c; 
C cinst; 
cinst.SomeTemplateFunction<int>(&a); 
cinst.SomeTemplateFunction<char>(&c);

Thorsten's answer gives you a class function but in the comments you state you are looking for a normal member function.

type
  TMyClass = class
  public
    procedure DoStuff<T>(var a: T);
  end;

procedure TMyClass.DoStuff<T>(var a: T);
begin
end;

...
var
  instance: TMyClass;
  i: Integer;
  s: string;
...
  instance.DoStuff<Integer>(i);
  instance.DoStuff<string>(s);

However, what I'm struggling with is how exactly you could do anything very useful with this, in Delphi, that could not be done just as effectively without a generic solution.

I'd appreciate any suggestions and would be happy to edit the answer to accommodate them.

You can move the generic parameter from the class to the method, and use var instead of a pointer type:

type
  TMyGeneric = record
    class procedure DoStuff<T>(var aParam: T); static;
  end;

var
  int : Integer;
  s   : string;
...
TMyGeneric.DoStuff<Integer>(int);
TMyGeneric.DoStuff<string>(s);

EDIT: Unfortunately the Delphi compiler doesn't seem to be able to perform type inference when var parameters are used which makes it necessary to explicitly specify the generic paramter type using <..> on the method calls.

Without the "var" the <..> can be omitted (but then the method can no longer modify the passed in variable).

type
  Pointer<T> = record
  public type
    Ty = ^T;
  end;

Now you can use this generic pointer anywhere

type A = class
    procedure<T> DoStuff(tPtr: Pointer<T>.Ty);
end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM