2014-11-14 22 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

相關問題