C++ 类成员回调

C++ Class member callback

本文关键字:回调 成员 C++      更新时间:2023-10-16

我在编译此代码时出错:

template <class T> class purple_multitimer {
public:
typedef struct _timerinfo timerinfo, *ptimerinfo;
typedef gboolean (T::*multitimer_callback) (ptimerinfo pti);
typedef struct _timerinfo {
    guint id;
    multitimer_callback cb;
    T * pthis;
    purple_multitimer<T> * pmt;
} timerinfo, *ptimerinfo;
    purple_multitimer() {
        memset(m_ti, 0, sizeof(m_ti));
    }
    ~purple_multitimer() {
        stop();
    }
    void start(multitimer_callback mt_cb, T * pthis, guint timeout = 10) {
        ptimerinfo pti = ti_get();
        assert(pti);
        pti->pthis = pthis;
        pti->pmt = this;
        pti->cb = mt_cb;
        pti->id = purple_timeout_add_seconds(timeout, GSourceFunc(timeout_cb), pti);
    }
    void stop(multitimer_callback mt_cb = NULL) {
        for (register guint n = 0; n < sizeof(m_ti)/sizeof(timerinfo); ++ n)
            if (m_ti[n].cb == mt_cb) {
                purple_timeout_remove(m_ti[n].id);
                ti_zero(n);
            }
    }
private:
    timerinfo m_ti[32];
    inline ptimerinfo ti_get(guint n) {
        return &m_ti[n];
    }
    inline ptimerinfo ti_get() {
        for (register guint n = 0; n < sizeof(m_ti)/sizeof(timerinfo); ++ n)
            if (m_ti[n].id == 0) return &m_ti[n];
        return NULL;
    }
    inline ptimerinfo ti_zero(ptimerinfo pti) {
        memset(pti, 0, sizeof(timerinfo));
        return pti;
    }
    inline ptimerinfo ti_zero(guint n) {
        memset(&m_ti[n], 0, sizeof(timerinfo));
        return &m_ti[n];
    }
    static gboolean timeout_cb(ptimerinfo pti) {
        gboolean res = (pti->pthis->*(pti->cb))(pti);
        if (!res) pti->pmt->stop(pti->cb);
        return res;
    }
};
class _ctrl {
    public:
    purple_multitimer<_ctrl> pmt;
    gboolean on_tomeout (purple_multitimer<_ctrl>::ptimerinfo pti) {
        return false;
    };
    void on_connected(PurpleConnection *gc) {
        pmt.start(purple_multitimer<_ctrl>::multitimer_callback(&_ctrl::on_tomeout), this);
    }
    void on_disconnected(PurpleConnection *gc) {
    }
} controller;

编译此代码时出现错误:

[Error] E:dnc-imexchangednc-imexchange.cpp:117: error: no matching function for call to `purple_multitimer<_ctrl>::start(gboolean (_ctrl::*)(_timerinfo*), _ctrl* const)'
[Warning] E:dnc-imexchangednc-imexchange.cpp:52: note: candidates are: void purple_multitimer<T>::start(gboolean (T::*)(_timerinfo*), T*, guint) [with T = _ctrl]

我需要以这种方式实现回调。

如果你想要一些高质量的回调(能够一次调用多个函数,适合观察者模式),我可以建议 boost::signals2.

如果你只想调用一个函数作为回调,你可以使用 std::function:

void Foo(const std::function<bool (const int)> &callback)
{
    const int number = 4;
    if (callback(number))
    {
        std::cout << "Callback returned true!" << std::endl;
    }
    else
    {
        std::cout << "Callback returned false!" << std::endl;
    }
}
// Use this if you have C++11
void CallFooLambda()
{
    const auto lambda = [](const int number) -> bool
    {
        return number % 2;
    };
    Foo(lambda);
}
// Else use these functions
bool FooCallback(const int number)
{
    return number % 2;
}
void CallFoo()
{
    Foo(&FooCallback);    
}

_ctrl是一个常量指针,您尝试调用的函数需要非常量 ptr-to _ctrl (pthis)。

你能定义pthis如下吗?

T *pthis const

这应该使您的代码与错误消息中的"候选"匹配。

this是无法更改的指针。

Boost.Function 是一个很好的工具包,用于简化回调语法和实现。

Boost.Function 库包含一个 类模板系列,它们是 函数对象包装器。这个概念 类似于通用回调。 它与功能共享功能 指针都定义了调用 接口(例如,一个函数需要两个 整数参数并返回 浮点值),通过该值 可以调用一些实现,并且 调用的实现可以 在整个过程中的变化 程序。

一般来说,任何地方 函数指针将用于 推迟呼叫或回拨, Boost.Function 可以用于 允许用户在 目标的实施。 目标可以是任何"兼容的" 函数对象(或函数指针), 意思是 由 Boost.Function 指定的接口 可以转换为参数 目标函数对象。