Обратный вызов члена класса C ++ - PullRequest
1 голос
/ 11 мая 2011

У меня ошибка при компиляции этого кода:

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

Мне нужно реализовать обратные вызовы таким способом.

Ответы [ 4 ]

3 голосов
/ 11 мая 2011

Если вам нужны обратные вызовы хорошего качества (способные вызывать сразу несколько функций, подходящие для шаблона наблюдателя), могу ли я предложить boost :: сигналы2 .

Если вы просто хотите вызвать одну функцию в качестве обратного вызова, вы можете использовать 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);    
}
0 голосов
/ 11 мая 2011

Boost.Function является хорошим набором инструментов для упрощения синтаксиса и реализации обратного вызова.

Библиотека Boost.Function содержит семейство шаблонов классов, которые являются обертками объектов функций.Понятие аналогично обобщенному обратному вызову.Он разделяет функции с указателями на функции в том смысле, что оба определяют интерфейс вызова (например, функцию, принимающую два целочисленных аргумента и возвращающую значение с плавающей запятой), через которую может вызываться некоторая реализация, и вызываемая реализация может изменяться в течение всего процесса.программа.

Как правило, в любом месте, в котором указатель функции будет использоваться для отсрочки вызова или выполнения обратного вызова, вместо этого может использоваться Boost.Function, чтобы предоставить пользователю большую гибкость в реализации цели.Целями могут быть любые «совместимые» функциональные объекты (или указатели на функции), что означает, что аргументы интерфейса, обозначенного Boost.Function, могут быть преобразованы в аргументы целевого объекта функции.

0 голосов
/ 11 мая 2011

Можете ли вы определить pthis следующим образом?

T *pthis const

Это должно сделать ваш код соответствующим «кандидату» в сообщении об ошибке.

this - это указатель, который выне может измениться.

0 голосов
/ 11 мая 2011

_ctrl является константным указателем, и функция, которую вы пытаетесь вызвать, требует неконстантного ptr-to _ctrl (pthis).

...