2014-02-19 5 views
5

Ich möchte eine Art, so erklären:Warum lehnt der Compiler die Deklaration eines generischen 2D-Arrays ab?

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

Der Compiler weist mit:

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

Ich fragte mich, ob das Problem auf die Verschachtelung von Generika verbunden war. Aber es scheint nicht:

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

führt auch zu den gleichen Compiler-Fehler.

Der documentation für den Compiler-Fehler hat mich vielleicht noch weniger wissen, als ich wusste, bevor ich es lesen:

E2508 Typparameter auf diese Art nicht erlaubt (Delphi)

Wenn-Klasse Verweise können Sie nicht direkt generische Klassen verwenden. Sie müssen eine Wrapper-Klasse verwenden, um Generika verwenden zu können.

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. 

Kann mir jemand erklären, warum ich nicht generische Typen auf diese Weise erklären können?

+1

Sieht für mich wie ein Fehler aus. –

+0

'TDynMatrix = Array von Array von T;' kompiliert. –

+1

@LURD Ja, aber dann bin ich durch Oldschool-Zuweisungskompatibilität eingeschränkt. Der Vorteil von 'TArray <> ist, dass Sie dieser besonderen Tyrannei entkommen. –

Antwort

3

Ihr Code ist ungültig, weil Sie einen generischen Typ nicht als offenen generischen Typ deklarieren können.

Ich würde erklären dies als:

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

diese Weise können Sie immer noch die Kompatibilität, die Sie wahrscheinlich brauchen: die Elemente einer Dimension zu einem TArray<T>.

So können Sie

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

schreiben usw.

3

aktuell keine Gründe, aber dieser ist nicht auf tarray beschränkt,

die folgenden Typdefinitionen verwenden:

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

Ich habe versucht, alle Kombinationen:

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

Sie alle scheitern .

Sie können Typen mit komplexem Typ Ausdrücke erklären, wenn diese Typen nicht generisch für sich alleine:

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

Es gibt eine Umgehung ist. Sie können den Typ innerhalb einer Klasse mit einem Typparameter deklarieren.

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

So können Sie TTheClass<T>.TGenClassClass als Typ verwenden.

+1

das ist die Schlussfolgerung, die ich war zu lehnen, aber ich fragte mich, warum das so war. –

+1

Yup leider nicht, warum. –

1

FWIW, die durch die verschiedenen Kommentare und Antworten inspiriert, das ist der Code, den ich glaube, die am effektivsten ist:

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; 

Dies ermöglicht es so zu deklarierten Variablen sein:

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

Und machen neue Instanzen wie folgt aus:

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

Nun, wenn nur die allgemeine Schlußfolgerung c des Compilers Fähigkeiten waren ein wenig besser.

Verwandte Themen