为什么记录构造函数在内联函数中行为不端



在下面的代码中,记录构造函数做了一些奇怪的事情
它在所有情况下都可以正常工作,除了下面标记的行:

program Project9;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils,
  System.Generics.Collections;
type
  TIntegerPair = TPair<Integer, Integer>;
type
  TMiniStack<T> = record
  public
    Items: array[0..10] of T;
    SP: integer;
    procedure Init;
    procedure PushInline(const Item: T); inline;
    procedure PushNormal(const Item: T);
  end;
procedure TMiniStack<T>.Init;
begin
  FillChar(Items, SizeOf(Items), #0);
  SP:= 0;
end;
procedure TMiniStack<T>.PushInline(const Item: T);
begin
  Items[SP]:= Item;
  Inc(SP);
end;
procedure TMiniStack<T>.PushNormal(const Item: T);
begin
  Items[SP]:= Item;
  Inc(SP);
end;

procedure RecordConstructorFail;
var
  List1: TMiniStack<TIntegerPair>;
  List2: array[0..2] of TIntegerPair;
  Pair: TIntegerPair;
  a: string;
begin
  Writeln('start test...');
  FillChar(List1, SizeOf(List1), #0);
  List1.Init;
  List1.PushInline(TIntegerPair.Create(1, 1));
  List1.PushInline(Pair.Create(2, 2));   <<--- Failure
  List2[0]:= TIntegerPair.Create(1, 1);
  List2[1]:= Pair.Create(2, 2);
  if (List1.Items[0].Key <> 1) or (List1.Items[1].Key <> 2) then Writeln('something is wrong with List1-Inline');
  if (List2[0].Key <> 1) or (List2[1].Key <> 2) then Writeln('something is wrong with List1');
  List1.Init;
  List1.PushNormal(TIntegerPair.Create(1, 1));
  List1.PushNormal(Pair.Create(2, 2));
  if (List1.Items[0].Key <> 1) or (List1.Items[1].Key <> 2) then Writeln('something is wrong with List1-Normal');
  Writeln('Done');
  Readln(a);
  Writeln(a);
end;
begin
  RecordConstructorFail;
end.

为什么这条线路会导致故障?

List1.PushInline(Pair.Create(2, 2)); <<- Failure: Dumps the data somewhere else.

这是编译器错误吗
还是我错过了什么?

我使用的是Delphi XE6。

在我看来,无论是否内联,作为实例构造函数调用的表达式都不会计算为值。因此不能作为论据传递。想想

Pair.Create(...)

就好像这是一个过程。它没有任何价值。

在我看来,编译器应该拒绝代码,而它没有被拒绝的事实就是错误。

在我看来,当你不内联代码时,它似乎可以工作,这取决于偶然性。


不过这都是猜测。记录构造函数没有正确记录。构造函数的文档是针对类的,尚未更新以涵盖记录。类的文档说明实例形式是一个引用实例的表达式。

当使用对象引用(而不是类引用)调用构造函数时,它不会创建对象。相反,构造函数对指定的对象进行操作,只执行构造函数实现中的语句,然后返回对该对象的引用。

但这对记录来说没有多大意义,因为存在值类型而不是引用类型。

我的最佳猜测是,解析器将此表达式视为与实例相同的类型,因为类的构造函数就是这样。但代码生成实际上并没有产生价值。

最新更新