www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to overload member function pointer and a regualr member function

reply ParticlePeter <ParticlePeter gmx.de> writes:
I would like to have this kind of struct:

struct Foo {
   private int i;
   void function( int i, float f ) bar;  // will be defined at 
runtime
   void bar( float f ) {
     bar( i, f );
   }
}

But apparently the function pointer and the member function 
cannot have the same name: Error: function main.Foo.bar conflicts 
with variable main.Foo.bar ...

I tried with an inner struct:
struct Foo {
   private int i;
   void function( int i, float f ) bar;  // will be defined at 
runtime
   private struct Inner {
     void bar( float f ) {
       bar( i, f );
     }
   }
   Inner inner;
}

But this time I get following error:
Error: need 'this' for 'i' of type 'int'

What does this message tell me? Should the inner struct not be 
able to access Foo.i?

How else can I get the required behavior?

I would prefer to avoid another indirection like this:
struct Foo {
   private int i;
   void function( int i, float f ) bar;  // will be defined at 
runtime
   void baz( float f ) {
     bar( i, f );
   }
   void baz( int ii, float f ) {
     bar( ii, f );
   }
}
Apr 24
parent reply Basile B. <b2.temp gmx.com> writes:
On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote:
 I would like to have this kind of struct:

 struct Foo {
   private int i;
   void function( int i, float f ) bar;  // will be defined at 
 runtime
   void bar( float f ) {
     bar( i, f );
   }
 }

 [...]
 How else can I get the required behavior?
Like this: struct Foo1 { private void function(int,float) _bar; void bar(float){} void bar(int i, float f){_bar(i,f);} } Or like this: struct Foo2 { private void function(int,float) _bar; void bar(float) {} void function(int,float) bar() {return _bar;} } First solution looks better: (new Foo2).bar()(0,0f) // less good (new Foo1).bar(0,0f) // better
Apr 25
parent reply ParticlePeter <ParticlePeter gmx.de> writes:
On Tuesday, 25 April 2017 at 09:50:14 UTC, Basile B. wrote:
 On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote:
 I would like to have this kind of struct:

 struct Foo {
   private int i;
   void function( int i, float f ) bar;  // will be defined at 
 runtime
   void bar( float f ) {
     bar( i, f );
   }
 }

 [...]
 How else can I get the required behavior?
Like this: struct Foo1 { private void function(int,float) _bar; void bar(float){} void bar(int i, float f){_bar(i,f);} }
Thanks for your reply, but that's what I would like to avoid, the additional indirection to call the function pointer with the original argument count. Do you have any idea about the likelihood of the compiler removing this indirection as an optimizations?
Apr 25
parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 25 April 2017 at 15:43:48 UTC, ParticlePeter wrote:
 On Tuesday, 25 April 2017 at 09:50:14 UTC, Basile B. wrote:
 On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote:
Thanks for your reply, but that's what I would like to avoid, the additional indirection to call the function pointer with the original argument count.
Oops, i can believe i didn't read the last part of your question.
 Do you have any idea about the likelihood of the compiler 
 removing this indirection as an optimizations?
with pragma(inline, true), the function body should be injected at the call sites.
Apr 25
parent reply ParticlePeter <ParticlePeter gmx.de> writes:
On Tuesday, 25 April 2017 at 16:27:43 UTC, Basile B. wrote:
 On Tuesday, 25 April 2017 at 15:43:48 UTC, ParticlePeter wrote:
 On Tuesday, 25 April 2017 at 09:50:14 UTC, Basile B. wrote:
 On Monday, 24 April 2017 at 16:46:21 UTC, ParticlePeter wrote:
Thanks for your reply, but that's what I would like to avoid, the additional indirection to call the function pointer with the original argument count.
Oops, i can believe i didn't read the last part of your question.
 Do you have any idea about the likelihood of the compiler 
 removing this indirection as an optimizations?
with pragma(inline, true), the function body should be injected at the call sites.
This would not help I fear, the body of the function pointer is unknown in an external lib. I rather hoped that the compiler "sees" the parameter forwarding to the fp and is able to directly call it. Best thing would be for both overloads, but I would not know how to verify this.
Apr 25
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 04/25/2017 11:28 AM, ParticlePeter wrote:
 On Tuesday, 25 April 2017 at 16:27:43 UTC, Basile B. wrote:
 with pragma(inline, true), the function body should be injected at the
 call sites.
This would not help I fear, the body of the function pointer is unknown in an external lib. I rather hoped that the compiler "sees" the parameter forwarding to the fp and is able to directly call it. Best thing would be for both overloads, but I would not know how to verify
this. pragma(inline, true) works because all you need inlined in this case is the body of bar(int, float). The compiler does call the function pointer directly. import std.stdio; struct Foo1 { private void function(int,float) _bar; void bar(float f) { pragma(inline, true); writefln("Called with %s", f); } void bar(int i, float f) { pragma(inline, true); _bar(i,f); } } void func(int i, float f) { writefln("Called with %s and %s", i, f); } void main() { auto f = Foo1(&func); f.bar(1.5); f.bar(42, 2.5); } Compile with -inline (and perhaps with -O): dmd -inline deneme.d Generate the disassembly with obj2asm that comes with dmd (or with any other disassembly tool): obj2asm deneme.o > deneme.asm You can open deneme.asm in an editor and search for function "_Dmain:" in it. Here is what my dmd 2.074 produced: _Dmain: push RBP mov RBP,RSP sub RSP,010h mov RAX,_D6deneme4funcFifZv GOTPCREL[RIP] mov -010h[RBP],RAX movss XMM0,FLAT:.rodata[00h][RIP] movss -8[RBP],XMM0 lea RDX,_TMP0 PC32[RIP] mov EDI,0Eh mov RSI,RDX movss XMM0,-8[RBP] call _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv PLT32 mov EAX,02Ah movss XMM1,FLAT:.rodata[00h][RIP] movss -4[RBP],XMM1 mov RDI,RAX movss XMM0,-4[RBP] call qword ptr -010h[RBP] xor EAX,EAX leave ret add [RAX],AL .text._Dmain ends The call to jumbled writefln() is a direct call inside func(): call _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv PLT32 So, you're good... :) Ali
Apr 25
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 04/25/2017 11:54 AM, Ali Çehreli wrote:

 _Dmain:
         push    RBP
         mov    RBP,RSP
         sub    RSP,010h
         mov    RAX,_D6deneme4funcFifZv GOTPCREL[RIP]
         mov    -010h[RBP],RAX
         movss    XMM0,FLAT:.rodata[00h][RIP]
         movss    -8[RBP],XMM0
         lea    RDX,_TMP0 PC32[RIP]
         mov    EDI,0Eh
         mov    RSI,RDX
         movss    XMM0,-8[RBP]
         call      _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv PLT32
         mov    EAX,02Ah
         movss    XMM1,FLAT:.rodata[00h][RIP]
         movss    -4[RBP],XMM1
         mov    RDI,RAX
         movss    XMM0,-4[RBP]
         call    qword ptr -010h[RBP]
         xor    EAX,EAX
         leave
         ret
         add    [RAX],AL
 .text._Dmain    ends

 The call to jumbled writefln() is a direct call inside func():

         call      _D3std5stdio17__T8writeflnTaTfZ8writeflnFNfxAafZv PLT32
My analysis is wrong because that writefln() is for the bar(float) overload but I still think what you want is achieved. Ali
Apr 25
parent reply Basile B. <b2.temp gmx.com> writes:
On Tuesday, 25 April 2017 at 18:58:58 UTC, Ali Çehreli wrote:
 On 04/25/2017 11:54 AM, Ali Çehreli wrote:
 My analysis is wrong because that writefln() is for the 
 bar(float) overload but I still think what you want is achieved.

 Ali
No it's ok, it works. The additional indirection is well avoided: Let's take this module: ================== #!dmd -release -inline -O module runnable; struct Foo { private void function(int,float) _bar; void bar(float){} pragma(inline, false) void bar(int i, float f){_bar(i,f);} } struct FooInline { private void function(int,float) _bar; void bar(float){} pragma(inline, true) void bar(int i, float f){_bar(i,f);} } void testInlined(ref FooInline foo) { foo.bar(0,0); } void test(ref Foo foo) { foo.bar(0,0); } void main() { import disassembler, std.stdio; disassembler.symbolTable.addModule!runnable; prettyDisasm(&testInlined).writeln; prettyDisasm(&test, 2).writeln; // dig up to 2 levels, required for the indir. } ================== and looks at the output: ;------- SUB 0000000000459970h ------- ; NAMED: testInlined 0000000000459970h push rbp 0000000000459971h mov rbp, rsp 0000000000459974h sub rsp, 20h 0000000000459978h mov qword ptr [rbp-08h], rdi 000000000045997Ch xor edi, edi 000000000045997Eh mov dword ptr [rbp-20h], edi 0000000000459981h movss xmm0, dword ptr [rbp-20h] 0000000000459986h mov rax, qword ptr [rbp-08h] 000000000045998Ah call qword ptr [rax] 000000000045998Dh mov rsp, rbp 0000000000459990h pop rbp 0000000000459991h ret ;------------------------------------- ;------- SUB 0000000000459934h ------- ; XREFS: [00000000004599A6h] 0000000000459934h push rbp 0000000000459935h mov rbp, rsp 0000000000459938h sub rsp, 10h 000000000045993Ch mov qword ptr [rbp-08h], rdi 0000000000459940h mov rdi, rsi 0000000000459943h mov rax, qword ptr [rbp-08h] 0000000000459947h call qword ptr [rax] 000000000045994Ah mov rsp, rbp 000000000045994Dh pop rbp 000000000045994Eh ret ;------------------------------------- ;------- SUB 0000000000459994h ------- ; NAMED: test 0000000000459994h push rbp 0000000000459995h mov rbp, rsp 0000000000459998h sub rsp, 10h 000000000045999Ch xor esi, esi 000000000045999Eh mov dword ptr [rbp-10h], esi 00000000004599A1h movss xmm0, dword ptr [rbp-10h] 00000000004599A6h call 0000000000459934h 00000000004599ABh mov rsp, rbp 00000000004599AEh pop rbp 00000000004599AFh ret ;------------------------------------- - testInlined() contains only the delegate call. (call qword ptr [rax]) - test() contains a call (call 0000000000459934h) which contains the delegate call (call qword ptr [rax]) Actually i've even had to add (pragma inline false) to show the difference since DMD inlined automatically bar() in test().
Apr 26
parent ParticlePeter <ParticlePeter gmx.de> writes:
On Wednesday, 26 April 2017 at 08:24:08 UTC, Basile B. wrote:
 On Tuesday, 25 April 2017 at 18:58:58 UTC, Ali Çehreli wrote:
 On 04/25/2017 11:54 AM, Ali Çehreli wrote:
 My analysis is wrong because that writefln() is for the 
 bar(float) overload but I still think what you want is 
 achieved.

 Ali
No it's ok, it works. The additional indirection is well avoided: Let's take this module: ================== #!dmd -release -inline -O module runnable; struct Foo { private void function(int,float) _bar; void bar(float){} pragma(inline, false) void bar(int i, float f){_bar(i,f);} } struct FooInline { private void function(int,float) _bar; void bar(float){} pragma(inline, true) void bar(int i, float f){_bar(i,f);} } void testInlined(ref FooInline foo) { foo.bar(0,0); } void test(ref Foo foo) { foo.bar(0,0); } void main() { import disassembler, std.stdio; disassembler.symbolTable.addModule!runnable; prettyDisasm(&testInlined).writeln; prettyDisasm(&test, 2).writeln; // dig up to 2 levels, required for the indir. } ================== and looks at the output: ;------- SUB 0000000000459970h ------- ; NAMED: testInlined 0000000000459970h push rbp 0000000000459971h mov rbp, rsp 0000000000459974h sub rsp, 20h 0000000000459978h mov qword ptr [rbp-08h], rdi 000000000045997Ch xor edi, edi 000000000045997Eh mov dword ptr [rbp-20h], edi 0000000000459981h movss xmm0, dword ptr [rbp-20h] 0000000000459986h mov rax, qword ptr [rbp-08h] 000000000045998Ah call qword ptr [rax] 000000000045998Dh mov rsp, rbp 0000000000459990h pop rbp 0000000000459991h ret ;------------------------------------- ;------- SUB 0000000000459934h ------- ; XREFS: [00000000004599A6h] 0000000000459934h push rbp 0000000000459935h mov rbp, rsp 0000000000459938h sub rsp, 10h 000000000045993Ch mov qword ptr [rbp-08h], rdi 0000000000459940h mov rdi, rsi 0000000000459943h mov rax, qword ptr [rbp-08h] 0000000000459947h call qword ptr [rax] 000000000045994Ah mov rsp, rbp 000000000045994Dh pop rbp 000000000045994Eh ret ;------------------------------------- ;------- SUB 0000000000459994h ------- ; NAMED: test 0000000000459994h push rbp 0000000000459995h mov rbp, rsp 0000000000459998h sub rsp, 10h 000000000045999Ch xor esi, esi 000000000045999Eh mov dword ptr [rbp-10h], esi 00000000004599A1h movss xmm0, dword ptr [rbp-10h] 00000000004599A6h call 0000000000459934h 00000000004599ABh mov rsp, rbp 00000000004599AEh pop rbp 00000000004599AFh ret ;------------------------------------- - testInlined() contains only the delegate call. (call qword ptr [rax]) - test() contains a call (call 0000000000459934h) which contains the delegate call (call qword ptr [rax]) Actually i've even had to add (pragma inline false) to show the difference since DMD inlined automatically bar() in test().
Guys, you're great! Thanks a lot!
Apr 26