简体   繁体   English

一类作为从另一类回调的方法

[英]Method of one class as callback from another

I will describe my problem the simplest as I can. 我将尽可能简单地描述我的问题。

What is my issue: 我的问题是什么:

I have frist class as a singleton: 我有单身人士的第一课:

class CTimer1
{
public:
    static CTimer1 * getInstance();       //This gives me pointer to instance
    void setChannelA(uint8_t compareValue);
private:
    //Cnstructors
    CTimer1();  //Prevent consttuction but allow in getInstance
    CTimer1(const CTimer1&);    //Prevent construction by copying
    CTimer1& operator=(const CTimer1&); //Prevent assigment
    ~CTimer1();                 //Prevent unwanted destruction
    static CTimer1 * timerInstance;
    static bool isCreated;
};

And here is second class where I would like to have possibility to call setChannelA method from CTimer1 class as a setPwm method from CServo class: 这里是第二类,我想有可能调用setChannelA从方法CTimer1类作为setPwm从方法CServo类:

class CServo {
public:
    CServo();
    ~CServo();

public:
    //public methods
    void registerPwmTimer(void (*callback)(uint8_t u8_buffer));

    void (*setPwm)(uint8_t u8_buffer);   //As this method I would like to call setChannelA from CTimer1 class
};

Here is registerPwmTimer method: 这是registerPwmTimer方法:

void CServo::registerPwmTimer(void (*callback)(uint8_t u8_buffer))
{
    setPwm = callback;
}

Then I have tried to assign pointer to this method as a following: 然后,我尝试将指针分配给此方法,如下所示:

int main()
{   
    CTimer1 * timer1 = CTimer1::getInstance();
    CServo servo1();
    servo1.registerPwmTimer(timer1->setChannelA);
    servo1.setPwm(10);       //This is example how I want to call setChannelA method

    while(1)
    {

    }
}

I have error: 我有错误:

error: no matching function for call to 'CServo::registerPwmTimer(<unresolved overloaded function type>)'

What is important: 重要的是:

I can't use std::function because this is some part of code in C++ for embedded device, so I need to save memory consumption. 我不能使用std::function因为这是C ++中嵌入式设备代码的一部分,因此我需要节省内存消耗。 Is there any way that I will be able to achieve this effect? 有什么办法可以达到这种效果? If ony one possibility to do this is ot use some std library please for answers too. 如果只有一种可能是这样做,也请使用一些标准库。 Thanks for your help. 谢谢你的帮助。

Your problem is that a function pointer necessarily has to point to a static function. 您的问题是函数指针必须必须指向静态函数。 When you invoke an instance function (a method) there is a hidden first argument, which is the object on which the function was invoked. 当您调用实例函数(方法)时,会有一个隐藏的第一个参数,即在其上调用该函数的对象。 (This hidden argument is available as this within the function's definition.) (这个隐藏参数是可以作为this函数的定义。)

Your CServo::registerPwmTimer() function signature is simply incompatible with invocation of a member function; 您的CServo::registerPwmTimer()函数签名与成员函数的调用完全不兼容。 function pointers alone do not provide a way to bind an argument to the pointer, so even if you could convey the member function pointer using a (free) function pointer type, the hidden this argument could not be determined when the function pointer was invoked. 仅函数指针不能提供将参数绑定到指针的方法,因此,即使您可以使用(自由)函数指针类型来传递成员函数指针,也无法在调用函数指针时确定隐藏的this参数。

To put it another way, it would fail for the same reason that trying CTimer1::setChannelA(0) would fail -- you want to invoke that method, but you haven't communicated which object on which to invoke it. 换句话说,它会以与尝试CTimer1::setChannelA(0)失败相同的原因而失败-您想要调用该方法,但尚未传达在哪个对象上调用它。

Change the signature of CServo::registerPwmTimer to accept an std::function object instead of a raw function pointer. 更改CServo::registerPwmTimer的签名以接受std::function对象,而不是原始函数指针。 std::function objects can be constructed from function pointers, but they can also be constructed from lambdas, and some standard library functions return function objects: std::function对象可以从函数指针构造,但是它们也可以从lambda构造,并且某些标准库函数返回函数对象:

void registerPwmTimer(std::function<void(uint8_t)>);

Now, you can use std::bind to create a new function that binds the object instance to the member function pointer: 现在,您可以使用std::bind创建一个新函数,该函数将对象实例绑定到成员函数指针:

servo1.registerPwmTimer(std::bind(&CTimer1::setChannelA, timer1));

Note that std::bind does not extend the lifetime of the object pointed to by timer1 . 请注意, std::bind 不会延长timer1指向的对象的生存期。 If the returned function is invoked after that object is destructed, the result is undefined behavior. 如果在销毁该对象之后调用返回的函数,则结果将是未定义的行为。


Another alternative would be to accept both an instance and a pointer to a member function. 另一种选择是接受实例和指向成员函数的指针。 The problem with this approach is it requires using templates: 这种方法的问题在于它需要使用模板:

template <typename T>
void registerPwmTimer(void (T::*)(uint8_t), T&);

This isn't bad in itself, but what you'll wind up doing is creating a polymorphic wrapper class so that you can insert this into your callback list alongside other callbacks that don't share the same T . 这本身并不是一件坏事,但是您最终要做的是创建一个多态包装器类,以便您可以将其与其他不共享T回调一起插入到回调列表中。 At that point, you're just recreating std::function , since std::function already serves the purpose of being a polymorphic wrapper around callable things. 到那时, 您只是在重新创建std::function ,因为std::function已经实现了成为可调用事物周围的多态包装的目的。


To illustrate the mess of implementing a polymorphic callable wrapper yourself, here is a very light example. 为了说明自己实现多态可调用包装器的麻烦,这是一个非常简单的示例。 I will show the declarations of a set of these types, and link to an example implementation. 我将显示一组这些类型的声明,并链接到示例实现。

This is the base type, with a pure virtual operator() that serves as the invocation operation. 这是基本类型,具有纯虚拟的operator()作为调用操作。

class poly_callable
{
public:
    virtual void operator()(int) const = 0;
};

Now we have a type for function pointers (also works with pointer-to-functor): 现在,我们有了函数指针的类型(也适用于指向指针的函数):

template <typename T>
class fn_poly_callable : public poly_callable
{
public:
    typedef T fn_type;

    fn_poly_callable(T);
    virtual void operator()(int) const;

private:
    T fn;
};

And one for member functions -- oh, but const member functions and non- const member functions are not interchangeable, so we need an extra template parameter for that: 还有一个用于成员函数-哦,但是const成员函数和非const成员函数不可互换,因此我们需要一个额外的模板参数:

template <typename T, typename M = void (T::*)(int)>
class member_poly_callable : public poly_callable
{
public:
    typedef T object_type;
    typedef M member_fn_type;

    member_poly_callable(member_fn_type, object_type&);
    virtual void operator()(int) const;

private:
    member_fn_type mfn;
    object_type& target;
};

Plus we'll want some helper functions to allow the compiler to infer the template types. 另外,我们将需要一些帮助函数来允许编译器推断模板类型。 One for function pointers: 一种用于函数指针:

template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(T fn)
{
    return std::unique_ptr<poly_callable>(new fn_poly_callable<T>(fn));
}

Two for member functions ( const and non- const ): 两个用于成员函数( const和non- const ):

template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int), T& target)
{
    return std::unique_ptr<poly_callable>(new member_poly_callable<T>(mfn, target));
}

template <typename T>
std::unique_ptr<poly_callable> make_poly_callable(void (T::*mfn)(int) const, T& target)
{
    return std::unique_ptr<poly_callable>(new member_poly_callable<T, void (T::*)(int) const>(mfn, target));
}

If you want to see it all in action, I made a "simple" and working example . 如果您想看到所有功能,我了一个“简单”的示例

So... just use std::function . 所以...只需使用std::function There's no reason to reinvent this stuff. 没有理由重新发明这些东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM