如何在c ++中传递泛型函数指针?

时间:2014-08-15 16:34:09

标签: c++ pointers

我想要完成的是在嵌入式环境中注册回调。此回调将采用以下两种形式之一:

void (*cb) (void *ctxt); or
void ClassA::VirtualFn (void);

此代码仅在使用GCC的ARM平台上运行。由于在运行时完成一些动态绑定,寄存器回调函数必须是虚拟的。上述两个函数在汇编级别上都是等效的(它们都采用单个指针)。此外,回调机制是为了性能目的而组装的,因为它发生在ISR上下文中,因此我不必担心这一点。我真正需要的是一个函数,它接受上述任何一个并存储传递的函数指针和上下文指针。即:

void isr_cb (void *ctxt) {}
gpio->RegisterIsr (isr_cb, cptr);
gpio->RegisterIsr (&ClassA::IsrHandler, this);

我已经通过将虚拟成员函数转换为 (void (*) (void *)) 来测试了这一点,实际上一切都按预期工作(除了编译器警告)。

3 个答案:

答案 0 :(得分:1)

virtual成员函数投射到void (*)(void *)听起来像是一种严厉的做法。

你说:

  

由于在运行时完成了一些动态绑定,寄存器回调函数必须是虚拟的。

我认为你有一个ClassA类型的对象。如果这是正确的,那么你应该:

  1. static ClassA成员注册到其签名为的回调机制:

    void (*)(ClassA& ref);
    
  2. 添加完成实际工作的virtual成员函数。

    void doStuff();
    
  3. 假设注册的回调函数是:

    static void foo(Class& ref);
    

    foo的实施中,在doStuff上致电ref

    static void foo(Class& ref)
    {
       ref.doStuff();
    }
    

答案 1 :(得分:0)

如果您可以在c ++ 11或std::bind中使用boost::bind,您将会有更轻松的时间。如果接口(即实际输出类型和实际输入参数类型相同),两者都可以让成员函数指针和自由函数相互混合,例如。

int f(double val)
{

}

class A {

   int memberf(double val);

}

A instanceOfA;
auto f1 = std::bind(f, std::placeholders::_1);
auto f2 = std::bind(&A::memberf, &instanceOfA, std::placeholders::_1);

f1f2现在都是采用double并返回int的函数,与一个是成员函数而另一个是成员函数无关自由功能,不需要演员表。我不得不承认我无法从内存中写出实际的类型。

答案 2 :(得分:0)

首先,在C和C ++中没有泛型函数指针这样的东西。

尽管如此,仍然可以采用完全一致且高性能的解决方案。

由于非成员函数已经是正确的类型,因此它是微不足道的。

  1. 如果您知道可能要传递的全部非虚拟成员函数和虚拟函数插槽,请为每个插槽定义一个简单的转发器,如下所示:

    void forward_to_IsrHandler(void* p) {
        ((ClassA*)p)->IsrHandler();
    }
    gpio->RegisterIsr (forward_to_IsrHandler, (void*)this);
    
  2. 如果你不知道,或者真的想在表演的祭坛上牺牲标准一致性,你可以convert your member-function-pointer to a normal function-pointer (gcc extension, other compilers have their own)

    void (*tmp)(ClassA*) = (void(*)(ClassA*))&ClassA::IsrHandler;
    

    使用-Wno-pmf-conversions删除使用扩展程序时的警告 因为对函数void(*)(void*)void(*)(ClassA*)的调用在ARM上看起来完全相同,所以你可以使用它,即使它严格来说是UB:

    gpio->RegisterIsr ((void(*)(void*))tmp, (void*)this);
    

  3. Selectively disabling GCC warnings for only a small code-segment

    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wno-pmf-conversions"
        // Do the foul deed here
    #pragma GCC diagnostic pop