Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 792
Hal Avatar asked Mar 17 '11 19:03

Hal


People also ask

How do you declare a generic pointer?

When a variable is declared as being a pointer to type void it is known as a generic pointer. Since you cannot have a variable of type void, the pointer will not point to any data and therefore cannot be dereferenced. It is still a pointer though, to use it you just have to cast it to another kind of pointer first.

What is generic pointer How can be it converted to a specific type of pointer?

Generic pointers can be specified using the type void *, where the keyword void represents the absence of specific type information, or using the built-in type alias uintptr_t which is aliased to an unsigned integer type of size appropriate for a pointer in the current data model.

What is a generic pointer explain with an example?

The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage. This means that it points to the address of variables. It is also called the general purpose pointer. In C, malloc() and calloc() functions return void * or generic pointers.

What is a generic pointer in C++?

The void pointer, also known as the generic pointer, is a special type of pointer that can be pointed at objects of any data type! A void pointer is declared like a normal pointer, using the void keyword as the pointer's type: void* ptr; // ptr is a void pointer.


2 Answers

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 (i.e. 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.

like image 116
David Heffernan Avatar answered Sep 28 '22 13:09

David Heffernan


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).

like image 35
Thorsten Engler Avatar answered Sep 28 '22 14:09

Thorsten Engler