본문 바로가기

Dev Language/C++11

[C++11] Signals and Slots

반응형

몇몇 개발 플랫폼을 사용하면서 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;

}



반응형