为什么编译器坚持我的功能是内联的,当它不是? [英] Why does the compiler insist my function is inline when it's not?
问题描述
为什么我收到
[DCC错误] ProjectCOWArray.dpr(23):E2426内联函数不能有asm块
程序ProjectCOWArray;
{$ APPTYPE CONSOLE}
{$ R * .res}
type
PRefCount = ^ TRefCount;
TRefCount = array [0..1] of integer;
TCOWArray< T> = record
private
fData:TArray< T>
private
procedure IncRefCount; << - not inline
end;
{TCOWArray< T> }
procedure TCOWArray< T> .IncRefCount;
asm
{$ if defined(win32)}
mov eax,fData;
lock inc dword ptr [eax - 8];
{$ ifend}
{$ if defined(win64)}
mov rax,fData;
lock inc dword ptr [rax -12];
{$ ifend}
end;
begin
end。
Delphi XE2没有 AtomicIncrement
我如何解决这个问题?
它想保留汇编器,因为否则我不能有锁
前缀,我不想使用 InterlockedIncrement
,因为这是一个WinAPI函数,我不想那种开销。
这是因为泛型功能是在内联引擎之上实现的。适用于内联函数的相同限制适用于通用函数。编译器写程序没有采取额外的步骤来使错误消息特定于泛型而不是内联函数。
我认为调用 InterlockedIncrement
可能是最好的选择,对于没有 AtomicIncrement
内在。或者,创建自己的版本 AtomicIncrement
,这只是在Delphi的版本中定义的,不包括它。这个函数可以写成asm。当然,它显然必须用asm写。
{$ IFNDEF AtomicFunctionsAvailable}
function AtomicIncrement目标:整数):整数;
asm
....
end;
{$ ENDIF}
或者如@TLama建议,您可以使用<$ c $
使用 System.SyncObjs
单元中的 SetLength(...)
实现写数组的副本。例如,这里有一个非常简单的写数组实现的副本:
单元COWArray;
interface
type
TCOWArray< T> = record
private
FItems:TArray< T>
function GetLength:Integer;
procedure SetLength(Value:Integer);
function GetItem(Index:Integer):T;
procedure SetItem(Index:Integer; const Value:T);
public
类函数New(const Values:T的数组):TCOWArray< T>静态的;
属性长度:整数读取GetLength write SetLength;
属性Items [索引:Integer]:T读取GetItem write SetItem;默认;
end;
实现
function TCOWArray< T> .GetLength:Integer;
begin
结果:= System.Length(FItems);
end;
procedure TCOWArray< T> .SetLength(Value:Integer);
begin
System.SetLength(FItems,Value); // SetLength enforces uniqueness
end;
function TCOWArray< T> .GetItem(Index:Integer):T;
begin
结果:= FITEMs [Index];
end;
procedure TCOWArray< T> .SetItem(Index:Integer; const Value:T);
begin
System.SetLength(FItems,System.Length(FItems)); // SetLength enforces uniqueness
FItems [Index]:= Value;
end;
类函数TCOWArray< T> .New(const Values:T array):TCOWArray< T>
var
i:Integer;
begin
System.SetLength(Result.FItems,System.Length(Values));
for i:= 0 to high(Values)do
Result.FItems [i]:= Values [i];
end;
end。
Why am I getting
[DCC Error] ProjectCOWArray.dpr(23): E2426 Inline function must not have asm block
program ProjectCOWArray;
{$APPTYPE CONSOLE}
{$R *.res}
type
PRefCount = ^TRefCount;
TRefCount = array[0..1] of integer;
TCOWArray<T> = record
private
fData: TArray<T>;
private
procedure IncRefCount; <<-- not inline
end;
{ TCOWArray<T> }
procedure TCOWArray<T>.IncRefCount;
asm
{$if defined(win32)}
mov eax,fData;
lock inc dword ptr [eax - 8];
{$ifend}
{$if defined(win64)}
mov rax,fData;
lock inc dword ptr[rax -12];
{$ifend}
end;
begin
end.
Delphi XE2 does not have AtomicIncrement
, so how do I solve this issue?
It'd like to retain the assembler, because otherwise I cannot have the lock
prefix in and I do not want to use InterlockedIncrement
because that's a WinAPI function and I do not want that kind of overhead.
This is because the generics functionality is implemented on top of the inlining engine. The same restrictions that apply to inline functions apply to generic functions. The compiler writers just haven't taken the extra step to make the error messages specific to generics rather than inline functions.
I think that calling InterlockedIncrement
is probably your best option, for Delphi versions that don't have the AtomicIncrement
intrinsic. Or, alternatively, create your own version of AtomicIncrement
, that is only defined in versions of Delphi that do not include it. And that function can be written in asm. Well, it clearly has to be written in asm of course.
{$IFNDEF AtomicFunctionsAvailable}
function AtomicIncrement(var Target: Integer): Integer;
asm
....
end;
{$ENDIF}
Or as @TLama suggests, you can use TInterlocked
from the System.SyncObjs
unit to provide atomic operations.
With all that said, I see no need to meddle with the internals in this way. Implement a copy of write array by calling SetLength(...)
whenever you write to the array. For instance, here's a very simple copy on write array implementation:
unit COWArray;
interface
type
TCOWArray<T> = record
private
FItems: TArray<T>;
function GetLength: Integer;
procedure SetLength(Value: Integer);
function GetItem(Index: Integer): T;
procedure SetItem(Index: Integer; const Value: T);
public
class function New(const Values: array of T): TCOWArray<T>; static;
property Length: Integer read GetLength write SetLength;
property Items[Index: Integer]: T read GetItem write SetItem; default;
end;
implementation
function TCOWArray<T>.GetLength: Integer;
begin
Result := System.Length(FItems);
end;
procedure TCOWArray<T>.SetLength(Value: Integer);
begin
System.SetLength(FItems, Value); // SetLength enforces uniqueness
end;
function TCOWArray<T>.GetItem(Index: Integer): T;
begin
Result := FItems[Index];
end;
procedure TCOWArray<T>.SetItem(Index: Integer; const Value: T);
begin
System.SetLength(FItems, System.Length(FItems)); // SetLength enforces uniqueness
FItems[Index] := Value;
end;
class function TCOWArray<T>.New(const Values: array of T): TCOWArray<T>;
var
i: Integer;
begin
System.SetLength(Result.FItems, System.Length(Values));
for i := 0 to high(Values) do
Result.FItems[i] := Values[i];
end;
end.
这篇关于为什么编译器坚持我的功能是内联的,当它不是?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!