gpt4 book ai didi

delphi - E2009 不兼容的类型 : 'Parameter lists differ'

转载 作者:行者123 更新时间:2023-12-03 15:09:12 25 4
gpt4 key购买 nike

我收到以下错误:

E2009 Incompatible types: 'Parameter lists differ'



但是我不同意,查看定义我看不出有什么区别。

Looks the same to me...

这是记录定义:
type
TFastDiv = record
private
...
DivideFunction: function (const Buffer: TFastDiv; x: integer): integer;

这是我要分配的 Mod 函数:
function dividefixedi32(const Buffer: TFastDiv; x: integer): integer;
asm

以下分配发出错误:
class operator TFastDiv.Implicit(a: integer): TFastDiv;
begin
if (a = 0) then begin
raise EDivByZero.Create('Setting a zero divider is a division by zero error')
at ReturnAddress;
end;
Result.FSign:= Math.sign(a);
case Result.FSign of
-1: begin
SetDivisorI32(Result, a);
Result.DivideFunction:= dividefixedi32; <<-- error E2009

我的代码有什么问题?

南昌
unit SSCCE;

interface

uses Math;

type
TFastDiv = record
private
FBuffer: UInt64; // The reciprocal of the divider
FDivider: integer; // The divider itself (need with modulus etc).
FSign: TValueSign;
DivideFunction: function (const Buffer: TFastDiv; x: integer): integer;
ModFunction: function (const Buffer: TFastDiv; x: integer): integer;
public
class operator Implicit(a: integer): TFastDiv;
end;


implementation

uses SysUtils;

function dividefixedi32(const Buffer: TFastDiv; x: integer): integer; forward;

class operator TFastDiv.Implicit(a: integer): TFastDiv;
begin
if (a = 0) then begin raise EDivByZero.Create('Setting a zero divider is a division by zero error') at ReturnAddress; end;
Result.FSign:= Math.sign(a);
case Result.FSign of
-1: begin
//SetDivisorI32(Result, a);
Result.DivideFunction:= dividefixedi32;
end; {-1:}
1: begin
//SetDivisorU32(Result.FBuffer, a);
end; {1:}
end; {case}
Result.FDivider:= a;
end;

function dividefixedi32(const Buffer: TFastDiv; x: integer): integer;
asm
mov eax, edx
mov r8d, edx // x
mov r9, rcx // Buffer
imul dword [r9] // m
lea eax, [rdx+r8] // r8 = r8 or rsi
mov ecx, [r9+4] // shift count
sar eax, cl
sar r8d, 31 // sign(x)
sub eax, r8d
ret
end;

end.

最佳答案

首先,一些一般性建议。你的 SSCCE 很差。它既不简短也不独立。这其实是比较重要的。使演示代码尽可能短通常有助于您理解问题。这绝对是这里的情况。

这是我对 SSCCE 的看法:

program soq19147523_version1;

type
TRecord = record
data: Integer;
proc: procedure(const rec: TRecord);
end;

procedure myproc(const rec: TRecord);
begin
end;

procedure foo;
var
rec: TRecord;
begin
rec.proc := myproc; // fail, E2009
end;

begin
end.

这无法与 E2009 编译。您可以通过多种方式使其编译。例如,删除 data成员导致编译成功。
program soq19147523_version2;

type
TRecord = record
proc: procedure(const rec: TRecord);
end;

procedure myproc(const rec: TRecord);
begin
end;

procedure foo;
var
rec: TRecord;
begin
rec.proc := myproc; // compiles
end;

begin
end.

在 XE3 中,您可以通过添加 [ref] 使其编译属性到过程类型的参数。明确地说,这在 XE3 中编译:
program soq19147523_version3;

type
TRecord = record
data: Integer;
proc: procedure(const [ref] rec: TRecord);
end;

procedure myproc(const [ref] rec: TRecord);
begin
end;

procedure foo;
var
rec: TRecord;
begin
rec.proc := myproc; // compiles in XE3, no [ref] in XE2
end;

begin
end.

这为我们提供了关于编译器正在做什么的强有力的线索。一个未装饰的 const记录参数通过值或引用传递。如果记录小到足以放入寄存器,则将按值传递。

编译器在处理记录时,还没有完全确定记录的大小。我猜在编译器内部有一个包含记录大小的变量。在记录的声明完成之前,我假定这个大小变量为零。所以编译器决定 const记录类型的参数将在寄存器中按值传递。当程序 myproc遇到,记录的真实大小是已知的。它不适合寄存器,因此编译器会识别出不匹配。记录中的类型按值接收其参数,但提供用于赋值的类型按引用传递参数。

确实,您可以删除 [ref]来自 myproc 的声明并且程序仍然可以编译。

这也解释了为什么您发现使用 var参数导致编译成功。这显然强制通过引用传递参数。

如果您可以移动到 XE3 或更高版本,那么解决方案很明显:使用 [ref]强制编译器的手。

如果你不能移动到 XE3 那么也许是一个无类型的 const参数是最好的解决方案。这也强制编译器通过引用传递参数。
program soq19147523_version4;

type
TRecord = record
data: Integer;
proc: procedure(const rec{: TRecord});
end;

procedure myproc(const rec{: TRecord});
begin
Writeln(TRecord(rec).data);
end;

procedure foo;
var
rec: TRecord;
begin
rec.proc := myproc;
end;

begin
end.

经常阅读我在 Stack Overflow 上的帖子的读者会知道,我是值类型记录上的运算符重载的大力支持者。我广泛使用此功能,它会生成高效且高度可读的代码。但是,当您开始努力使用更复杂和相互依赖的类型时,设计和实现就会崩溃。

这个问题中突出显示的缺陷就是一个很好的例子。期望编译器可以处理这个问题并不少见。期望类型能够引用自身是非常合理的。

另一个实现让程序员失望的例子是当你希望放置一个 const 时。该记录中的记录类型。例如,考虑这种类型:
type
TComplex = record
public
R, I: Double;
const
Zero: TComplex = (R: 0.0, I: 0.0);
end;

这无法在 Zero 的声明处编译E2086 类型“TComplex”尚未完全定义。

另一个限制是类型 A 无法引用类型 B,反之亦然。我们可以对类进行前向声明,但不能对记录进行前向声明。我知道需要修改编译器实现以支持这一点,但当然可以实现。

还有更多。为什么不允许记录继承?不想多态,只想继承记录的数据成员和方法。我什至不需要你在类中得到的行为。那是我不介意 TDerivedRecord不是 TBaseRecord .我想要的只是继承成员和函数以避免重复。

可悲的是,在我看来,这是一个已经完成 90% 的功能,只是缺少完成它所需的温柔、关爱。

关于delphi - E2009 不兼容的类型 : 'Parameter lists differ' ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19147523/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com