Параметр, введенный в массив, не принимается при перегрузке функции

#delphi #overloading

#delphi #перегрузка

Вопрос:

В 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 таким, какой он есть (не строковый тип), это значительно упрощает обработку чтения и записи. Я предпочитаю не присваивать его переменной, прежде чем передавать ее, потому что функция будет использоваться много..

Комментарии:

1. Могу я спросить, какие точные свойства TFourCC типа вы хотели бы сохранить?

2. @AndreasRejbrand Мне не нужен префикс длины байта, который имеет строка. Я не хочу, чтобы эти накладные расходы при чтении или записи в буфер или файл. И он должен быть читаемым человеком, поэтому использование 32-разрядного целочисленного типа также не идеально.

3. Хороший вопрос, компилятор ошибается

Ответ №1:

К сожалению, в настоящее время система типов работает именно так.

Но хорошей новостью является то, что вы можете творить чудеса с записями и перегрузкой оператора. Например, с

 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;
  

К сожалению, я очень спешу прямо сейчас, поэтому я не могу перепроверить правильность или прокомментировать дальше прямо сейчас!

Комментарии:

1. Спасибо! Кажется, что требуется много усилий для чего-то относительно простого, но это, несомненно, делает свое дело.

2. Мне также нужно иметь возможность сравнивать FOURCCS, поэтому для моей цели я добавил операторы классов Equal и NotEqual .

3. @Pantalaimon: Да, эти дополнения очень естественны.

4. Было бы неплохо добавить операторы класса для преобразования в / из String / Char, чтобы избежать предупреждения о неявных приведениях.

5. @fpiette: Действительно, записи с перегрузкой оператора — это очень гибкая и мощная функция, которая позволяет вам адаптировать тип к вашим собственным потребностям.