2014-11-14 113 views
0

我试图重新编码一些相当丑陋的模板编码。使用模板编码静态实例方法trampoline函数

仅供参考,原来是在这里:https://codereview.stackexchange.com/questions/69545/recode-c-c-trampoline-function-macros-using-templates

class Final : Base 
{ 
    void Foo(){...} 
    void Bar(){...} 

    static void init(){ 
     // register_method populates a table of "extern C" function pointers. 
     register_method("foo", & FooHandler); 
     register_method("bar", & BarHandler); 
    } 
    : 
    // trampolines 
    static void FooHandler(void* pInstance) { 
     Final* f = reinterpret_cast<Final*>(pInstance); 
     f->Foo(); 
    } 
    static void BarHandler(void* pInstance) { 
     Final* f = reinterpret_cast<Final*>(pInstance); 
     f->Bar(); 
    } 
} 

我与CPython的(C库)代码的接口。 Python运行时看到“myInst.foo”查找“foo”的表中,并调用:

Final::FooHandler(pointer_to_myInst); 

(注意有可能强制转换一个静态方法来C函数指针)

FooHandler蹦床到Final的正确实例的Foo方法。

实际上,句柄并不那么干净,并且有很多方法都需要相同的处理程序(但具有不同的函数地址)。

我试图抽象处理机制引入一个基类,像这样:

class Final : Base<Final> 
{ 
    void Foo(){...} 
    void Bar(){...} 

    static void init(){ 
     // register_method populates a table of "extern C" function pointers. 
     register_method("foo", & Foo, Handler< &Foo>); 
     register_method("bar", & Bar, Handler< &Bar>); 
    } 
    : 
} 

class Base<Final> 
{ 
    typedef void (Final::*FuncSig)(void); 
    typedef void (Final::*HandlerSig)(void*); // takes 1 pvoid param 

    void register_method(std::string name, FuncSig meth, HandlerSig handler) { 
     ...   
    } 

    // generic trampoline 
    template< Sig sig> 
    static void Handler(void* pInstance) { 
     Final* f = reinterpret_cast<Final*>(pInstance); 
     f ->* sig(); 
    } 
} 

我目前陷在编译器错误(http://ideone.com/vOtbcD),所以我甚至不能确定是否技术是有效的。

有没有办法做到这一点,或者这只是其中一个真正需要宏的地方?

仅供参考,原来是在这里:https://codereview.stackexchange.com/questions/69545/recode-c-c-trampoline-function-macros-using-templates

可以看出,原来的用途,而难看的宏。

+1

好对于初学者'Base'不是模板类,你需要使用关键字'template'。您可能还想阅读['std :: function'](http://en.cppreference。com/w/cpp/utility/functional/function)和['std :: bind'](http://en.cppreference.com/w/cpp/utility/functional/bind)。 – 2014-11-14 16:06:57

回答

2

register_method需要静态,如果你打算从静态init函数调用它。

调用通过一个成员函数指针的成员函数需要一个额外的组括号:(f->*sig)();

通过这些适当的,你的测试用例编译在C++ 11模式。也就是说,你有没有考虑用std::functionstd::bind来代替?很难说不知道register_method会做什么,但它可能会变得更清洁。

+0

谢谢,我已经充实了测试用例,为register_method提供了一个主体 – 2014-11-14 16:37:42

0

下面的代码工作的ideone(http://ideone.com/vOtbcD):

#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; 
} 

注:(Eelis上IRC)gcc就没有能够解决的函数地址传递给函数的模板专门化。你可以解决它要么通过声明独立变量的函数指针,或者使用肮脏投(或一个很好的铸像的boost :: implicit_cast)

我已经把这段代码进行审查:https://codereview.stackexchange.com/questions/69876/static-to-instance-method-trampolining-with-templates