2011-03-17 12 views
9

que tienen una clase como esta:¿Cómo puedo declarar un puntero basado en un tipo genérico?

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

Pero cuando intento compilar, Delphi me da este error:

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

¿Cómo puedo utilizar un puntero a un tipo parametrizado en un procedimiento Delphi ? No quiero hacer que toda la clase sea una clase de plantilla.

Respuesta

11

Para ello, tiene que declarar un tipo de puntero como un tipo anidado en la clase genérica:

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

Y si quieres un método de clase (es decir, no un método de instancia), puede hacerlo de esta manera :

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

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

O usando un parámetro var:

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

parece que es común el uso de recor ds en lugar de clases para tipos genéricos que nunca se crean instancias.

Por último, no se puede tener, en Delphi, un método genérico sin hacer que la clase sea genérica. En otras palabras, no hay análogo del siguiente código C++ plantilla:

respuesta de Thorsten muestra cómo implementar un método genérico sin hacer la clase genérica, que es el análogo de Delphi de la siguiente C código de la plantilla ++:

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

La respuesta de Thorsten le da una función de clase, pero en los comentarios indica que está buscando una función de miembro normal.

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

Sin embargo, lo que estoy luchando con es exactamente cómo se podía hacer nada muy útil con esto, en Delphi, que no se podía hacer con la misma eficacia y sin una solución genérica.

Agradecería cualquier sugerencia y estaría encantado de editar la respuesta para acomodarlos.

+0

@ David: ¿Estás seguro de que es la única manera? La única razón por la que hice de la función una función de clase es para poder usar genéricos, y no quiero que el usuario de la clase cree una nueva instancia de la clase para cada tipo diferente con el que quiera usar la función. De hecho, un requisito es que el usuario pueda usar la misma función con diferentes parámetros de tipo en la misma instancia de una clase. Si esta es realmente la única manera, es una limitación que deja alucinada a Delphi. – Hal

+0

@David Tengo otra instancia de este problema donde no puede ser un método de clase. Por favor responde mi pregunta en el comentario anterior. – Hal

+0

@Hal lo he respondido. Nunca tendría una instancia del tipo genérico en la sección del segundo código de la respuesta actualizada. Usted simplemente lo llama 'MyGeneric .DoStuff (@int);' Es un poco prolijo, pero así es como lo hace. –

4

Puede mover el parámetro genérico de la clase con el método, y el uso de var en lugar de un tipo de puntero:

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: Por desgracia, el compilador de Delphi no parece ser capaz de realizar la inferencia de tipos cuando se usan los parámetros var, lo que hace necesario especificar explícitamente el tipo de parámetro genérico usando < ..> en las llamadas a métodos.

Sin la "var" la < ..> se puede omitir (pero el método ya no puede modificar la variable pasada).

+0

+1 Cool. No sabía que pudieras hacer esto (¡evidentemente!) Sin embargo, eso no es un compilador para mí. Creo que necesitas: 'TMyGeneric.DoStuff (int)'. –

+0

Tiene razón, con "var" necesita usar . No tenía una razón para utilizar la inferencia de tipo para los parámetros var antes y cometí el error de suponer que funciona tan bien como con los parámetros que no son var. Claramente, el compilador de Delphi está aún más limitado con los genéricos de lo que pensaba. La inferencia de tipo funciona si dejas fuera la "var", pero supongo que el Interrogador preguntó sobre los punteros porque intenta modificar la variable pasada, por lo que omitir la var no es una opción. –

+0

Creo que debería editar su ejemplo para que compile y corrija el párrafo final. –

Cuestiones relacionadas