为什么编译器拒绝2D通用数组的声明?

时间:2014-02-19 19:38:42

标签: delphi generics

我想声明一个这样的类型:

type
  TDynMatrix<T> = TArray<TArray<T>>;

编译器拒绝这一点:

[dcc32 Error] E2508 Type parameters not allowed on this type

我想知道这个问题是否与泛型的嵌套有关。但似乎不是:

type
  TDynArray<T> = TArray<T>;//pointless type I know, but for the sake of the Q

也会导致相同的编译错误。

编译器错误的documentation让我知道在读之前可能比我知道的还要少:

  

此类型不允许使用E2508类型参数(Delphi)

     

使用类引用时,不能直接使用泛型类。   您需要使用包装类才能使用泛型。

program E2508;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TMyClass = class
  end;
  TMyClassClass<T> = class of TMyClass;

begin
   Writeln('FAIL - E2508 type parameters not allowed on this type');
end.

有谁可以解释为什么我不能用这种方式声明泛型类型?

3 个答案:

答案 0 :(得分:3)

抱歉没有理由,但这个不仅限于TArray,

使用以下类型定义:

TGenClass<T> = class fx: T; end;
TGenArray<T> = array of T;
TGenRecord<T> = record fx: T; end;
TGenProc<T> = procedure(const A: T);

我尝试了所有组合:

TGenClassClass<T> = TGenClass<TGenClass<T>>;
TGenClassArray<T> = TGenClass<TGenArray<T>>;
TGenClassRecord<T> = TGenClass<TGenClass<T>>;
TGenClassProc<T> = TGenClass<TGenClass<T>>;

TGenArrayClass<T> = TGenArray<TGenClass<T>>;
TGenArrayArray<T> = TGenArray<TGenArray<T>>;
TGenArrayRecord<T> = TGenArray<TGenClass<T>>;
TGenArrayProc<T> = TGenArray<TGenClass<T>>;

TGenRecordClass<T> = TGenRecord<TGenClass<T>>;
TGenRecordArray<T> = TGenRecord<TGenArray<T>>;
TGenRecordRecord<T> = TGenRecord<TGenClass<T>>;
TGenRecordProc<T> = TGenRecord<TGenClass<T>>;

TGenProcClass<T> = TGenProc<TGenClass<T>>;
TGenProcArray<T> = TGenProc<TGenArray<T>>;
TGenProcRecord<T> = TGenProc<TGenClass<T>>;
TGenProcProc<T> = TGenClass<TGenProc<T>>;

他们都失败了。

如果这些类型不是通用的,您可以声明具有复杂类型表达式的类型:

TClassClass = TGenClass<TGenClass<Integer>>;
TClassArray = TGenClass<TGenArray<Integer>>;
TClassRecord = TGenClass<TGenClass<Integer>>;
TClassProc = TGenClass<TGenClass<Integer>>;

TArrayClass = TGenArray<TGenClass<Integer>>;
TArrayArray = TGenArray<TGenArray<Integer>>;
TArrayRecord = TGenArray<TGenClass<Integer>>;
TArrayProc = TGenArray<TGenClass<Integer>>;

TRecordClass = TGenRecord<TGenClass<Integer>>;
TRecordArray = TGenRecord<TGenArray<Integer>>;
TRecordRecord = TGenRecord<TGenClass<Integer>>;
TRecordProc = TGenRecord<TGenClass<Integer>>;

TProcClass = TGenProc<TGenClass<Integer>>;
TProcArray = TGenProc<TGenArray<Integer>>;
TProcRecord = TGenProc<TGenClass<Integer>>;
TProcProc = TGenClass<TGenProc<Integer>>;

有规避。您可以使用类型参数在类中声明类型。

type
  TTheClass<T> = class
  type
    TGenClassClass = TGenClass<TGenClass<T>>;
  end;

因此,您可以使用TTheClass<T>.TGenClassClass作为类型。

答案 1 :(得分:3)

您的代码无效,因为您无法将泛型类型重新声明为开放泛型类型。

我会将其声明为:

type
  TDynMatrix<T> = array of TArray<T>;

通过这种方式,您仍然可以使用兼容性:一维到TArray<T>的元素。

那么你可以写

var
  matrix: TDynMatrix<Integer>;
  values: TArray<Integer>;
....
SetLength(matrix, 2, 2);
values := matrix[0];
values := Copy(matrix[1]);

等。

答案 2 :(得分:1)

FWIW受各种评论和答案的启发,这是我认为最有效的代码:

type
  TDynMatrix<T> = array of TArray<T>;
  TDynMatrix = class
  public
    class function New<T>(const Source: array of TArray<T>): TDynMatrix<T>; static;
  end;

class function TDynMatrix.New<T>(const Source: array of TArray<T>): TDynMatrix<T>;
var
  i: Integer;
begin
  SetLength(Result, Length(Source));
  for i := 0 to high(Result) do begin
    Result[i] := Copy(Source[i]);
  end;
end;

这允许声明这样的变量:

var
  RealM: TDynMatrix<Real>;
  ComplexM: TDynMatrix<TComplex>;

并制作这样的新实例:

RealM := TDynMatrix.New<Real>([TArray<Real>.Create(...)]);
ComplexM := TDynMatrix.New<TComplex>([TArray<TComplex>.Create(...)]);

现在,如果只有编译器的通用推理功能更好一点。