2014-11-14 6 views
0

오히려 못생긴 템플릿 코딩을 다시 코딩하려고합니다. 참고로템플릿으로 인스턴스 메소드 trampoline 함수 코딩하기

원래는 여기 : CPython의 (C 라이브러리)와 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(); 
    } 
} 

내 코드 인터페이스. 파이썬 런타임 "myInst.foo"을보고, 표에 "foo는"조회하고 호출 :

Final::FooHandler(pointer_to_myInst); 

FooHandler의 트램폴린을 (C의 함수 포인터에 고정 방법을 타입 변환 할 수 있습니다) 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

: 당신은 함수 포인터에 대해 별도의 변수를 선언하거나, 내가에서 검토이 코드까지 넣어 가지고 더러운 캐스트 (또는 부스트 :: implicit_cast 같은 멋진 캐스트)

를 사용하여 중 하나를 해결할 수 있습니다 기본 클래스'Template'는 템플릿 클래스가 아니기 때문에'template' 키워드가 필요합니다. ['std :: function'] (http : //en.cppreference.co.kr/w/cpp/utility/functional/function) 및 ['std :: bind'] (http://en.cppreference.com/w/cpp/utility/functional/bind)를 참조하십시오. –

답변

2

register_method은 정적 init 함수에서 호출하려는 경우 정적이어야합니다. 멤버 함수 포인터를 통해 멤버 함수를 호출

괄호의 추가 설정이 필요합니다 장소에 그와 (f->*sig)();

을, 테스트 케이스는 C++ 11 모드에서 컴파일합니다. 즉, std::functionstd::bind을 대신 사용하여이 문제를 해결했다고 생각하십니까? register_method이 무엇인지 알지 못하면 실제로 어떻게 보이는지 알기가 어렵지만 조금 더 깨끗해집니다.

+0

감사합니다. register_method의 본문을 제공하기 위해 테스트 케이스를 완성했습니다. –

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

참고 : (IRC에 Eelis) GCC는 함수의 주소를 확인 할 수 없습니다 알려져있다 템플릿 전문화가 기능에 전달되었습니다. 잘 https://codereview.stackexchange.com/questions/69876/static-to-instance-method-trampolining-with-templates