【问题标题】:How can I declare a pointer based on a generic type?如何声明基于泛型类型的指针?
【发布时间】:2011-03-17 19:52:15
【问题描述】:

我有这样的课:

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

但是当我尝试编译时,Delphi 给了我这个错误:

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

如何在 Delphi 过程中使用指向参数化类型的指针?我不想让整个类成为模板类。

【问题讨论】:

    标签: delphi generics pointers parameters delphi-2010


    【解决方案1】:

    为此,您需要在泛型类中将指针类型声明为嵌套类型:

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

    如果你想要一个类方法(即不是实例方法),你可以这样做:

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

    或者使用 var 参数:

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

    对于永远不会被实例化的泛型类型,使用记录而不是类似乎很常见。

    最后,在 Delphi 中,如果不使类成为泛型,就不能拥有泛型方法。换句话说,没有以下 C++ 模板代码的类似物:

    Thorsten 的回答展示了如何在不使类泛型的情况下实现泛型方法,即以下 C++ 模板代码的 Delphi 类似物:

    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 的回答为您提供了一个类函数,但在您声明的 cmets 中,您正在寻找一个普通的成员函数。

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

    但是,我正在努力解决的问题是,在 Delphi 中,您究竟如何能够做任何非常有用的事情,而没有通用解决方案则无法有效地完成。

    如果有任何建议,我将不胜感激,并很乐意编辑答案以适应它们。

    【讨论】:

    • @David:你确定这是唯一的方法吗?我将该函数设为类函数的唯一原因是我可以使用泛型,并且我不想让该类的用户为他想要使用该函数的每种不同类型创建一个新的类实例。事实上,一个要求是用户可以在一个类的同一个实例上使用具有不同类型参数的同一个函数。如果这真的是唯一的方法,那就是 Delphi 的一个令人震惊的限制。
    • @David 我有这个问题的另一个实例,它不能是类方法。请在上面的评论中回答我的问题。
    • @Hal 我已经回答了。在更新答案的第二个代码部分中,您永远不会有泛型类型的实例。你就叫它MyGeneric&lt;Integer&gt;.DoStuff(@int); 有点啰嗦,但你就是这么干的。
    • @David 不,你看错了。我说:其实有个要求是用户可以在同一个类的实例上使用同一个函数,不同类型参数。这意味着他们必须能够做到mg.DoStuff&lt;Integer&gt;(@int); mg.DoStuff&lt;PAnsiChar&gt;(@pac);
    • @Hal,数组的元素总是连续的。数组存储块的地址始终与数组第一个元素的地址相同。尽管数组地址的语法可能会根据您拥有的数组类型而有所不同,但获取第一个元素的地址的语法总是相同的,无论是开放数组、动态数组还是静态数组: @a[Low(a)].
    【解决方案2】:

    您可以将泛型参数从类移动到方法中,并使用 var 代替指针类型:

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

    编辑:不幸的是,当使用 var 参数时,Delphi 编译器似乎无法执行类型推断,这使得有必要在方法调用上使用 <..> 显式指定泛型参数类型。

    如果没有“var”,<..> 可以省略(但该方法不能再修改传入的变量)。

    【讨论】:

    • +1 酷。我不知道您可以这样做(显然!)但是,这对我来说不是编译器。我想你需要:TMyGeneric.DoStuff&lt;Integer&gt;(int).
    • 你是对的,“var”你需要使用。我之前没有理由对 var 参数使用类型推断,并且错误地假设它与非 var 参数一样有效。显然 Delphi 编译器对泛型的限制比我想象的还要多。如果您省略“var”,类型推断将起作用,但我假设提问者询问指针,因为他打算修改传入的变量,因此省略 var 不是一种选择。
    • 我认为您应该编辑您的示例以便编译,并更正最后一段。
    • 我想每个人都意识到 Delphi 编译器对泛型的限制比他们今天想象的还要多。我还注意到,使用泛型(在 RAD Studio 2010 中)Intellisense 很容易搞砸并认为模板化方法不存在,但它编译得很好。
    【解决方案3】:
    type
      Pointer<T> = record
      public type
        Ty = ^T;
      end;
    

    现在你可以在任何地方使用这个通用指针

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-01
      • 2013-06-13
      • 1970-01-01
      • 2018-12-14
      • 1970-01-01
      • 2010-10-22
      • 2015-12-14
      • 2019-04-02
      相关资源
      最近更新 更多