Array-typisierter Parameter wird bei Überladungsfunktion nicht akzeptiert

Sep 14 2020

In Delphi kann ich das tun:

Type
  TFourCC = Array[0..3] of AnsiChar;

Function Func(Param : TFourCC) : Boolean;
begin
  { ... }
end;

Func('ABCD'); // I can pass this as literal text without problems

Jetzt möchte ich diesen Parameter optional machen.

Function Func(Param : TFourCC = 'ABCD') : Boolean;
begin
  { ... }
end;

Jetzt wirft mir der Compiler einen Fehler: E2268 Parameters of this type cannot have default values

Ok, also dachte ich, eine Überladung der Funktion sollte dann den Trick machen ...

Function Func : Boolean; overload;
begin
  { ... }
end;

Function Func(Param : TFourCC) : Boolean; overload;
begin
  { ... }
end;

Func('ABCD'); // This line that worked in first example now gives an error

Leider mag Delphi das auch nicht. Wo es den Parameter zuerst als TFourCCtypisierte Variable akzeptiert hat , gibt es mir jetzt E2250 There is no overloaded version of 'Func' that can be called with these arguments.

Ich bin nicht einverstanden mit dem, was mir dieser Fehler sagt. Dasselbe hat funktioniert, wenn es nicht überladen war.

Kann mir jemand die Logik dahinter erklären und möglicherweise eine Lösung? Ich möchte das so lassen, TFourCCwie es ist (kein String-Typ), es erleichtert das Lesen und Schreiben erheblich. Ich vermeide es lieber, es zuerst einer Variablen zuzuweisen, bevor ich es übergebe, da die Funktion häufig verwendet wird .

Antworten

6 AndreasRejbrand Sep 14 2020 at 02:15

Leider funktioniert das Typsystem derzeit so.

Aber die gute Nachricht ist, dass Sie mit Aufzeichnungen und Überladung von Operatoren zaubern können. Zum Beispiel mit

type
  TFourCC = record
  strict private
    function GetChar(Index: Integer): AnsiChar;
    procedure SetChar(Index: Integer; const Value: AnsiChar);
  public
    class operator Implicit(AValue: AnsiString): TFourCC;
    class operator Implicit(AValue: TFourCC): AnsiString;
    class operator Equal(a, b: TFourCC): Boolean;
    class operator NotEqual(a, b: TFourCC): Boolean;
    property Chars[Index: Integer]: AnsiChar read GetChar write SetChar; default;
  case Boolean of
    False: (AnsiChars: array[0..3] of AnsiChar);
    True: (Data: Cardinal)
  end;

implementation

{ TFourCC }

class operator TFourCC.Implicit(AValue: AnsiString): TFourCC;
begin
  if Length(AValue) <> 4 then
    raise Exception.Create('Not a valid TFourCC string.');
  Result.Data := PCardinal(@AValue[1])^;
end;

class operator TFourCC.Implicit(AValue: TFourCC): AnsiString;
begin
  SetLength(Result, 4);
  PCardinal(@Result[1])^ := AValue.Data;
end;

class operator TFourCC.Equal(a, b: TFourCC): Boolean;
begin
  Result := a.Data = b.Data;
end;

class operator TFourCC.NotEqual(a, b: TFourCC): Boolean;
begin
  Result := a.Data <> b.Data;
end;

function TFourCC.GetChar(Index: Integer): AnsiChar;
begin
  Result := AnsiChars[Index];
end;

procedure TFourCC.SetChar(Index: Integer; const Value: AnsiChar);
begin
  AnsiChars[Index] := Value;
end;

Sie erhalten alle diese Vorteile:

procedure TForm1.FormCreate(Sender: TObject);
var
  x: TFourCC;
begin
  x := 'FINE';                     // implicit conversion from string
  ShowMessage(x);                  // implicit conversion to string
  x[0] := 'D';                     // can access parts for writing (without explicit member)
  ShowMessage(x);
  ShowMessage(x[0]);               // can access parts for reading (without explicit member)
  ShowMessage(x.Data.ToString);    // can access underlying storage as a 32-bit integer
end;

Und das können Sie jetzt tun

procedure f(A: TFourCC); overload;
begin
  ShowMessage(A);
end;

procedure f; overload;
begin
  ShowMessage('ABCD');
end;

Leider habe ich es gerade sehr eilig, daher kann ich die Richtigkeit oder den Kommentar im Moment nicht noch einmal überprüfen!