0

我正在尝试重新编码一些相当难看的模板编码。

作为参考,原文在这里:https ://codereview.stackexchange.com/questions/69545/recode-cc-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-cc-trampoline-function-macros-using-templates

可以看出,原始版本使用了相当丑陋的宏。

4

2 回答 2

2

register_method如果要从静态init函数调用它,则需要是静态的。

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

有了这些,您的测试用例就可以在 C++11 模式下编译。也就是说,您是否考虑过使用std::functionandstd::bind来代替?在不知道具体内容的情况下很难说出它实际上会是什么样子register_method,但它可能会变得更干净一些。

于 2014-11-14T16:08:54.423 回答
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 无法解析传递给函数的函数模板特化的地址。您可以通过为函数指针声明单独的变量或使用脏强制转换(或像 boost::implicit_cast 这样的漂亮强制转换)来解决它

我已将此代码放在以下位置进行审核:https ://codereview.stackexchange.com/questions/69876/static-to-instance-method-trampolining-with-templates

于 2014-11-14T18:20:40.357 回答