2013-10-02 27 views
5

aşağıdaki hatayı alıyorum 'Parametre listeleri farklılık'. İşte E2009 Uyumsuz türleri: Hiçbir farkı görebilirsiniz tanımları bakarak,</p> <blockquote> <p>E2009 Incompatible types: 'Parameter lists differ'</p> </blockquote> <p>Ancak ben katılmıyorum:

Looks the same to me...

rekor tanımı aşağıda verilmiştir:

type 
    TFastDiv = record 
    private 
    ... 
    DivideFunction: function (const Buffer: TFastDiv; x: integer): integer; 

Ve burada atamak istediğiniz Mod işlevi var:

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 
:

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

aşağıdaki atama hata verir

Kodumdaki sorun nedir?

SSCCE

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. 
+1

Denediğimde benim için iyi çalışıyor. Bir [SSCCE] görmeden (http: // sscce.org), tahminimce, muhtemelen birbiriyle çelişen çok sayıda 'TFastDiv' türü var. –

+0

Nope sadece TFastDiv kayıt tanımında var (dosyaların bulunmasında onaylanmış). – Johan

+0

@RemyLebeau, bir SSCCE – Johan

cevap

5

Her şeyden önce, bazı genel tavsiyeler. SSCCE'niz zayıf. Ne kısa ne de kendine yeten. Bu aslında oldukça önemli. Tanıtım kodunu mümkün olduğunca kısa hale getirmek sık sık sorunu anlamanıza yardımcı olur. Bu kesinlikle burada durumdur.

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. 

Bu E2009 ile derlenmeyecektir:

İşte bir SSCCE almak benim. Bir çok yolla derlemesini sağlayabilirsiniz. Örneğin, data üye kaldırma başarılı bir derleme sonuçlanır.

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 olarak bunu prosedürel Çeşidi parametreye [ref] özellik ekleyerek derleme yapabilirsiniz. açık olmak gerekirse, bu XE3 içinde derler:

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. 

Bu derleyici ne yaptığını ilişkin bize güçlü bir ipucu verir. Sonlandırılmamış bir const kayıt parametresi, değer veya başvuru olarak iletilir. Kayıt bir kayıt içine sığacak kadar küçükse, bu değer ile geçirilecektir.derleyici kaydını işlerken

, tam kaydın boyutu kesinleşmiş değil. Derleyicide dahili olarak, kaydın büyüklüğünü içeren bir değişken olduğunu tahmin ediyorum. Kayıt beyanı tamamlanana kadar, bu boyut değişkeninin sıfır olduğunu belirtiyorum. Bu nedenle derleyici, kayıt tipinin const parametresinin bir kayıttaki değere geçirileceğine karar verir. myproc prosedürü ile karşılaşıldığında, kaydın gerçek boyutu bilinir. Bir kayıt defterine sığmaz ve derleyici bu nedenle bir uyumsuzluğu tanır. Kayıttaki tip, parametresini değer olarak alır, ancak atama için sunulması parametreyi referans olarak geçirir.

Gerçekten de, myproc ilanı ve hala derler programdan [ref] kaldırabilirsiniz.

Ayrıca, neden bir var parametresi kullanıldığını başarılı bir derleme ile sonuçlandığını buldunuz. Bu açıkça, referans ile iletilecek parametreyi zorlar.

XE3 veya daha sonraya taşıyabiliyorsanız, çözüm açıktır: derleyicinin elini zorlamak için [ref] kullanın.

XE3'e taşıyamazsanız, belki de bir yazılmamış const parametresi en iyi çözümdür. Bu ayrıca, derleyiciyi parametreyi başvuruyla iletmeye zorlar. Burada Yığın taşması benim Yayınlarınızdan

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. 

Düzenli okuyucular I değer türü kayıtlarına aşırı operatörün büyük savunucusu olduğumu bilecek. Bu özelliği yoğun olarak kullanıyorum ve verimli ve okunabilir kodla sonuçlanıyor. Ancak, daha karmaşık ve birbirine bağlı türlerle zorlamaya başladığınızda, tasarım ve uygulama bozulur. kusur bu soruya vurgulanan

iyi bir örnektir. Derleyicinin bunu çözmesini beklemek pek alışılmamış bir şey değil. Bir türün kendisine atıfta bulunmasını beklemek çok mantıklıdır.

Uygulamanın, bu kayda bir const kayıt türünü koymak istediğinizde programcının aşağıya indirdiği başka bir örnek.

type 
    TComplex = record 
    public 
    R, I: Double; 
    const 
    Zero: TComplex = (R: 0.0, I: 0.0); 
    end; 

Bu E2086 Türü 'TComplex' henüz tam olarak bilinmemesine ile Zero ilanına en derlenmeyecektir: Örneğin, bu tip düşünün.

Diğer bir kısıtlama A tipi yetersizlik tersi B tipi bakın ve etmektir. Sınıflar için beyanlar yapabiliriz, ama kayıtlara değil. Derleyici uygulamasının bunu desteklemek için değiştirilmesinin gerekeceğini biliyorum, ancak bunu başarmak kesinlikle mümkün.

Ve daha fazlası var. Kayıtlar için mirasa izin vermek neden mümkün değil? Ben polimorfizm istemiyorum, sadece kayıtların veri üyelerini ve yöntemlerini miras almak istiyorum. Ve ben bile sınıfları ile aldığınız bir davranışa ihtiyacım yok. TDerivedRecordTBaseRecord değilse, bu umurumda değil. Tek istediğim, üyeliği devralmaktan kaçınmak ve üye olmak.

Ne yazık ki, aklıma göre, bu% 90'lık bir iştir ve ihaleyi tamamlamak için gerekli olan sevgi dolu ilgiyi, sadece ihale eksik.

+0

ekledim. Bu mükemmel bir şekilde açıklıyor. Remy'nin cevabı, 'veri üyeleri' ya da 'veri üyelerine' kıyasla aslında ayrımın 'program' ya da 'birim' olduğu düşüncesini çıkardı. Sadece benim günümü yaptın: - |), teşekkürler. – Johan

+0

Ayrıca bir türlenmemiş ödevi ile çalışmak gibi görünüyor: rec.proc: = @ myproc ({$ T-}). Derleyici muhtemelen çok beğenmez, bazen içsel bir hataya neden olur. –

+0

@SertacAkyuz Derleyicinin bunu –

2

Geçici çözüm

ben şöyle kodu değiştirirseniz:

kayıt tanım

type 
    TFastDiv = record 
    private 
    ... 
    DivideFunction: function (var Buffer: TFastDiv; x: cardinal): cardinal; 
           ^^^ 

fonksiyon definitio n

function dividefixedu32(var Buffer: TFastDiv; x: Cardinal): cardinal; // unsigned 
asm //     ^^^ 

sorun yanı uzağa gider.

var'u const olarak değiştirirseniz sorun devam eder.