2
\$\begingroup\$

I finally have a working trampoline mechanism. Would anyone care to critique it?

Ideone

#include <iostream>
using namespace std;
#include <map>
template<typename T>
class Base
{
public: 
 typedef void (T::*PFunc)(void);
 typedef void (*PHandler)(void*);
 using method_map_t = map< string, PHandler >;
 static method_map_t& methods( ) {
 static method_map_t* map_of_methods{};
 if( ! map_of_methods ) map_of_methods = new method_map_t;
 return *map_of_methods;
 }
 static void register_method( string name, PHandler handler ) {
 methods()[name] = handler;
 }
 // generic trampoline
 template<PFunc sig>
 static void Handler( void* pInstance ) {
 T* f = reinterpret_cast<T*>(pInstance);
 (f ->* sig)();
 }
};

...

class Final : Base<Final>
{
public:
 void Foo(){cout<<"got foo";}
 void Bar(){cout<<"got bar";}
 static void init(){
 // register_method populates a table of "extern C" function pointers.
 register_method( "foo", static_cast<PHandler>( &Handler<&Final::Foo> ) );
 register_method( "bar", static_cast<PHandler>( &Handler<&Final::Bar> ) );
 }
};
void InvokeFromC(void* inst, string name) {
 Base<Final>::PHandler h = Base<Final>::methods()[name];
 (*h)(inst);
}
int main() {
 Final* f = new Final{};
 f->init();
 // simulate invoking from C 
 InvokeFromC( f, "foo" );
 // your code goes here
 return 0;
}

This question follows from here.

asked Nov 14, 2014 at 18:32
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I will maintain my list of improvements in this answer.

There is a more succinct way to expose the mechanism to the consumer:

class Final : Base<Final>
{
 register_method<&Final::Foo>( "foo" ); //, static_cast<PHandler>( &Handler<&Final::Foo> ) );
 register_method<&Final::Bar>( "bar" ); //, static_cast<PHandler>( &Handler<&Final::Bar> ) );
 :
class Base
{
 :
 template<PFunc func>
 static void register_method( string name ) {
 methods()[name] = &Handler<func>;
 }
 :

This has extra advantage in that it avoids the following nasty issue:

Note: (Eelis on IRC) gcc is known not to be able to resolve addresses of function template specializations passed to functions. You can work around it either by declaring separate variables for the function pointers, or using a dirty cast (or a nice cast like boost::implicit_cast)

It doubles the number of templated functions getting generated: now 2 are generated for each method instead of one. But at a small price, it is much cleaner to the consumer!

Also function pointer typedef-s could be rewritten:

//typedef void (T::*PFunc)(void);
//typedef void (*PHandler)(void*);
using PFunc = void (T::*)(void);
using PHandler = void(*)(void);

http://ideone.com/ZFQb1f

answered Nov 14, 2014 at 21:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.