1

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

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.

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

我正在使用德尔福 XE6。

4

1 回答 1

2

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

Pair.Create(...)

好像这是一个程序。它没有产生任何价值。

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

在我看来,当您不内联代码时,代码似乎可以工作,这取决于机会。


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

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

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

我最好的猜测是解析器将此表达式视为与实例相同的类型,因为这就是类的构造函数的方式。但是 codegen 实际上并没有产生一个值。

于 2014-08-30T09:04:49.750 回答