Указатель на функцию-член C++, boost:: сигналы
У меня следующая ситуация (лучше в коде)
class Foo
{
private:
typedef boost::signal<void ()> Signal;
Signal signal;
public:
void Register_SignalFunction(const Signal::slot_type& slot);
void Unregister_SignalFunction(const Signal::slog_type& slot);
}
class OtherFoo
{
Foo foo;
public:
OtherFoo()
{
foo.Register_SignalFunction(&OnSignal) //I know I can't do this that is precisely my question.
}
void OnSignal(); //what to do when signal fires
}
Итак, вопрос в том, как передать указатель "функция-член" в метод Register. Кроме того, это нормально? Что мне нужно / нужно, так это какая-то система регистрации делегатов, поэтому, если кто-нибудь сможет направить меня в правильном направлении, я буду признателен. Спасибо заранее.
4 ответа
Вы бы обычно использовали boost bind:
foo.Register_SignalFunction (boost:: bind (& OtherFoo:: OnSignal, this));
Что тут происходит?:-)
Метод подключения сигнала принимает функтор. Это объект, который реализует оператор (). bind берет указатели на функции (либо для освобождения функций, либо для функций-членов) и возвращает функтор с правильной сигнатурой.
Также смотрите здесь:
Завершите пример, используя Boost::Signals для C++ Eventing
и здесь:
как boost:: function и boost:: bind работают
Чтобы отключить хранилище сигналов, возвращаемое значение из connect в:
boost::signals::connection
А затем вызовите метод отключения на этом.
Обычно вы либо делаете:
void Register_SignalFunction(const boost::function<void()> &slot) {
signal += slot;
}
Или, как встроенная функция:
template<typename T>
void Register_SignalFunction(T &slot) {
signal += slot;
}
Последний может быть немного более эффективным, удаляя слой косвенности boost::function
имеет - но только предполагая boost::signal
не использует boost::function
внутренне (что вполне вероятно). Так что используйте тот, который вы предпочитаете.
Я получил его после многих попыток, вот код:
GraphicsDeviceManager
{
private:
typedef boost::signal<void ()> DeviceLost;
DeviceLost deviceLost;
public:
Register_DeviceLostHandler(const boost::function<void ()> &handler)
{
deviceLost.connect(slot);
}
Unregister_DeviceLostHandler(const boost::function<void ()> &handler)
{
//deviceLost.disconnect(slot);
}
}
class GameBase
{
private:
GraphicsDeviceManager* graphics;
public:
GameBase()
{
graphics = new GraphicsDeviceManager();
graphics->Register_DeviceLostHandler(boost::bind(&GameBase::OnDeviceLost, this));
}
void OnDeviceLost()
{
//do some stuff
}
}
хорошо, этот код работает, как и должно быть, за одним исключением, если я раскомментирую инструкцию deviceLost.disconnect(handler), я получаю ошибки компиляции, такие как: ошибка C266 "boost::operator ==": 4 перегрузки имеют аналогичные преобразования.
Итак, почему это происходит? Вы знаете какой-нибудь другой способ выполнить то, что я пытаюсь?
В случае, если кто-то хочет полный пример:
#include <iostream>
#include <boost/signals2/signal.hpp>
#include <boost/bind.hpp>
#include <boost/optional/optional_io.hpp>
#define registerEvent_(A) registerEvent(boost::bind(A, this, _1, _2))
struct A
{
typedef boost::signals2::signal<int (int &, int &)> EventSignal;
typedef EventSignal::slot_type SlotType;
void registerEvent(const SlotType & slot);
void triggerAll(int& a1, int& a2);
EventSignal signal_;
};
void A::registerEvent(const SlotType & slot) { signal_.connect(slot); }
void A::triggerAll(int& a1, int& a2) {std::cout << signal_(a1, a2) << "\n";}
struct B : public A
{
B();
int myFunc(int& a1, int& a2);
};
B::B() {
#ifdef WITHMACRO
registerEvent_(&B::myFunc);
#else
registerEvent(boost::bind(&B::myFunc, this, _1, _2));
#endif
}
int B::myFunc(int& a1, int& a2) { return a1 + a2 + 1; }
int main()
{
int a1 = 2;
int a2 = 3;
B b;
b.triggerAll(a1, a2);
}