具有重载函数的编译器错误

Compiler bug with overloaded function

下面的代码给出了堆栈溢出:

function Func(x : Double) : Double; overload;
function Func(x : Integer) : Double; overload;


function Func(x : Double) : Double;
begin
  Result := Func(Round(x));
end;


function Func(x : Integer) : Double;
begin
  Result := 1.0;
end;

永远不会调用 Integer 重载函数,Double 重载函数会调用自身直到堆栈溢出。

以下代码按预期工作:

function Func2(x : Double) : Double; overload;
function Func2(x : Integer) : Double; overload;

function Func2(x : Double) : Double;
var
  ix : Integer;
begin
  ix := Round(x);
  Result := Func(ix);
end;


function Func2(x : Integer) : Double;
begin
  Result := 1.0;
end;

这是编译器错误还是预期行为?

System.Round 函数产生一个 Int64 值。

我认为编译器保留 Func 函数的 Double 重载比 Integer 重载更合适。

事实上,如果参数的值超过 Integer 的类型 min-max(从 -2147483648 到 2147483647,参见 System.Integer),Integer 重载可能会导致信息丢失.

Integer 参数更改为 Int64 参数将解决问题并避免信息丢失。

function Func(x : Double) : Double; overload;
function Func(x : Int64) : Double; overload;

...

function Func(x : Double) : Double;
begin
  Result := Func(Round(x));
end;

function Func(x : Int64) : Double;
begin
  Result := 1.0;
end;

我怀疑这是意料之中的事情。

问题是编译器内部 Round 函数 returns 一个 64 位整数。 CodeInsight 和 the official documentation 都告诉我这一点。如果编译器必须在采用 32 位整数或双精度的例程之间进行选择,则在给定 64 位整数时,它会选择接受双精度的例程。

要验证这一点,请尝试

procedure Test(x: Double); overload;
begin
  ShowMessage('double');
end;

procedure Test(x: Integer); overload;
begin
  ShowMessage('integer');
end;

procedure TForm5.FormCreate(Sender: TObject);
begin
  Test(Int64.MaxValue)
end;