重载函数时不接受数组类型参数

Array typed parameter not accepted when overloading function

在Delphi中,我可以这样做:

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

现在,我想将此参数设为可选。

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

现在,编译器向我抛出一个错误:E2268 Parameters of this type cannot have default values

好的,所以我在想重载函数应该可以解决问题...

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

不幸的是,Delphi 也不喜欢这样。它首先接受参数作为 TFourCC 类型变量,现在它给了我 E2250 There is no overloaded version of 'Func' that can be called with these arguments.

我不同意这个错误告诉我的内容,同样的事情在它没有超载时也有效。

有人可以向我解释这背后的逻辑,以及可能的解决方案吗?我想保持 TFourCC 原样(不是字符串类型),这样可以更轻松地处理读写。我宁愿避免在传递它之前先将其分配给变量,因为该函数将被使用 alot..

不幸的是,这就是当前类型系统的工作方式。

但好消息是您可以对记录和运算符重载施展魔法。例如,

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;

您将获得所有这些好处:

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;

而且,您现在可以做到

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

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

不幸的是,我现在非常很匆忙,所以我现在不能double-check正确性或进一步评论!