몇몇 개발 플랫폼을 사용하면서 QT의 Signal과 Slot과 같은 것을 가장 유용하게 사용하였다.
하지만 이런 기능들은 해당 프레임워크를 모두 가져와야 사용할 수 있기 때문에 문제가 발생할 가능성이 있다.
그래서 구글링해서 찾은 방법이 http://simmesimme.github.io/tutorials/2015/09/20/signal-slot
QT의 Signal Slot만큼 많은 기능들을 제공하지 않지만,
다른 플랫폼과 의존성을 없애면서 Signal Slot을 활용할 수 있다.
(내가 QT에서 console로 프로그램을 개발할 때 QT를 버리지 못하는 것 중 가장 큰 부분이 Signal/Slot 때문...)
메인 코드는 아래와 같습니다. ( 출처 : http://simmesimme.github.io/tutorials/2015/09/20/signal-slot )
(오직 std로 구현된 template class입니다.)
#ifndef SIGNAL_HPP
#define SIGNAL_HPP
#include <functional>
#include <map>
// A signal object may call multiple slots with the
// same signature. You can connect functions to the signal
// which will be called when the emit() method on the
// signal object is invoked. Any argument passed to emit()
// will be passed to the given functions.
template <typename... Args>
class Signal {
public:
Signal() : current_id_(0) {}
// copy creates new signal
Signal(Signal const& other) : current_id_(0) {}
// connects a member function to this Signal
template <typename T>
int connect_member(T *inst, void (T::*func)(Args...)) {
return connect([=](Args... args) {
(inst->*func)(args...);
});
}
// connects a const member function to this Signal
template <typename T>
int connect_member(T *inst, void (T::*func)(Args...) const) {
return connect([=](Args... args) {
(inst->*func)(args...);
});
}
// connects a std::function to the signal. The returned
// value can be used to disconnect the function again
int connect(std::function<void(Args...)> const& slot) const {
slots_.insert(std::make_pair(++current_id_, slot));
return current_id_;
}
// disconnects a previously connected function
void disconnect(int id) const {
slots_.erase(id);
}
// disconnects all previously connected functions
void disconnect_all() const {
slots_.clear();
}
// calls all connected functions
void emit(Args... p) {
for(auto it : slots_) {
it.second(p...);
}
}
// assignment creates new Signal
Signal& operator=(Signal const& other) {
disconnect_all();
}
private:
mutable std::map<int, std::function<void(Args...)>> slots_;
mutable int current_id_;
};#endif /* SIGNAL_HPP */
예제 1.
#include "Signal.hpp"
#include <iostream>
int main() {
// create new signal
Signal<std::string, int> signal;
// attach a slot
signal.connect([](std::string arg1, int arg2) {
std::cout << arg1 << " " << arg2 << std::endl;
});
signal.emit("The answer:", 42);
return 0;
}
예제 2.
#include "Signal.hpp"
#include <iostream>
class Button {
public:
Signal<> on_click;
};
class Message {
public:
void display() const {
std::cout << "Hello World!" << std::endl;
}
};
int main() {
Button button;
Message message;
button.on_click.connect_member(&message, &Message::display);
button.on_click.emit();
return 0;
}