digitalmars.D.learn - How to overload member function pointer and a regualr member function
- ParticlePeter (41/41) Apr 24 2017 I would like to have this kind of struct:
- Basile B. (18/29) Apr 25 2017 Like this:
- ParticlePeter (6/27) Apr 25 2017 Thanks for your reply, but that's what I would like to avoid, the
- Basile B. (4/11) Apr 25 2017 with pragma(inline, true), the function body should be injected
- ParticlePeter (6/19) Apr 25 2017 This would not help I fear, the body of the function pointer is
- =?UTF-8?Q?Ali_=c3=87ehreli?= (61/68) Apr 25 2017 this.
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/30) Apr 25 2017 My analysis is wrong because that writefln() is for the bar(float)
- Basile B. (84/88) Apr 26 2017 No it's ok, it works. The additional indirection is well avoided:
- ParticlePeter (2/93) Apr 26 2017 Guys, you're great! Thanks a lot!
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 2017
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 2017
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. Do you have any idea about the likelihood of the compiler removing this indirection as an optimizations?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);} }
Apr 25 2017
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:Oops, i can believe i didn't read the last part of your question.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.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 2017
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: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.On Tuesday, 25 April 2017 at 09:50:14 UTC, Basile B. wrote:Oops, i can believe i didn't read the last part of your question.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.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 2017
On 04/25/2017 11:28 AM, ParticlePeter wrote:On Tuesday, 25 April 2017 at 16:27:43 UTC, Basile B. wrote: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... :) Aliwith 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
Apr 25 2017
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 PLT32My analysis is wrong because that writefln() is for the bar(float) overload but I still think what you want is achieved. Ali
Apr 25 2017
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. AliNo it's ok, it works. The additional indirection is well avoided: Let's take this module: ================== 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 2017
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:Guys, you're great! Thanks a lot!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. AliNo it's ok, it works. The additional indirection is well avoided: Let's take this module: ================== 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 2017