Can I transfer GCC to a built-in deferred call through a stored function pointer?

Naturally, C ++ compilers can perform built-in function calls from a function template when a call to an internal function is directly known in this area ( ref ).

#include <iostream> void holyheck() { std::cout << "!\n"; } template <typename F> void bar(F foo) { foo(); } int main() { bar(holyheck); } 

Now, if I pass holyheck to a class that stores a pointer to a function (or equivalent) and then calls it? Do I have any hope that you will do this? How?

 template <typename F> struct Foo { Foo(F f) : f(f) {}; void calledLater() { f(); } private: F f; }; void sendMonkeys(); void sendTissues(); int main() { Foo<void(*)()> f(sendMonkeys); Foo<void(*)()> g(sendTissues); // lots of interaction with f and g, not shown here f.calledLater(); g.calledLater(); } 

My Foo type is designed to highlight tons of logic; it will be created several times. The specific function called from calledLater is the only thing that differs from instances (although it never changes over the lifetime of Foo ), so half of Foo 's goal is to respect DRY. (The rest of his goal is to keep this mechanism isolated from other code.)

But I do not want to introduce the overhead of the actual additional function call at the same time, because this all happens in the bottleneck of the program.

I am not saying ASM, so analyzing the compiled code is not very useful to me. My instinct is that I have no chance to insert here.

+3
c ++ c ++ 03
source share
3 answers

If you really do not need to use a pointer to a function, then the functor must do a trivial optimization:

 struct CallSendMonkeys { void operator()() { sendMonkeys(); } }; struct CallSendTissues { void operator()() { sendTissues(); } }; 

(Of course, C ++ 11 has lambdas, but you noted your C ++ 03 question.)

Having different instances of Foo with these classes and not having an internal state in these classes, f() does not depend on how the construction of f was built, so this is not a problem if the compiler cannot say that it remains unchanged.

+5
source share

In your example, what after firmware to compile it looks like this:

 template <typename F> struct Foo { Foo(F f) : f(f) {}; void calledLater() { f(); } private: F f; }; void sendMonkeys(); void sendTissues(); int main() { Foo<__typeof__(&sendMonkeys)> f(sendMonkeys); Foo<__typeof__(&sendTissues)> g(sendTissues); // lots of interaction with f and g, not shown here f.calledLater(); g.calledLater(); } 

clang ++ (3.7 as of a few weeks ago, which means that I expect clang ++ 3.6 to do this, since it is only a few weeks older in the source database) generates this code:

  .text .file "calls.cpp" .globl main .align 16, 0x90 .type main,@function main: # @main .cfi_startproc # BB#0: # %entry pushq %rax .Ltmp0: .cfi_def_cfa_offset 16 callq _Z11sendMonkeysv callq _Z11sendTissuesv xorl %eax, %eax popq %rdx retq .Ltmp1: .size main, .Ltmp1-main .cfi_endproc 

Of course, without the definition of sendMonkeys and sendTissues, we can no longer embed.

If we implement them as follows:

 void request(const char *); void sendMonkeys() { request("monkeys"); } void sendTissues() { request("tissues"); } 

assembler code will look like this:

 main: # @main .cfi_startproc # BB#0: # %entry pushq %rax .Ltmp2: .cfi_def_cfa_offset 16 movl $.L.str, %edi callq _Z7requestPKc movl $.L.str1, %edi callq _Z7requestPKc xorl %eax, %eax popq %rdx retq .L.str: .asciz "monkeys" .size .L.str, 8 .type .L.str1,@object # @.str1 .L.str1: .asciz "tissues" .size .L.str1, 8 

What if you cannot read the assembler code, this is request("tissues") and request("monkeys") as expected.

I am just amazed that g ++ 4.9.2. doesn't do the same (I got this far and expected to continue, "and g ++ does the same, I'm not going to publish code for it"). [He does inline sendTissues and sendMonkeys , but does not take the next step for inline request ]

Of course, it’s quite possible to make small changes to this and NOT get the code as a string — for example, add some conditions depending on variables that the compiler cannot determine at compile time.

Edit: I added a string and an integer to Foo and updated them using an external function, after which the attachment was deleted for both clang and gcc. Using JUST an integer and calling an external function, it embeds the code.

In other words, it really depends on the code being in the // lots of interaction with f and g, not shown here section. And I think that you (Ease) have been here long enough to know that for 80% + questions, this is code that is not posted in the question, which is the most important part for the actual answer;)

+1
source share

To make your original approach work, use

 template< void(&Func)() > struct Foo { void calledLater() { Func(); } }; 

In general, I was lucky that I got gcc inline functions using function references, not function pointers.

+1
source share

All Articles