Skip to content

Instantly share code, notes, and snippets.

@aspschn
Last active January 27, 2022 07:24
Show Gist options
  • Select an option

  • Save aspschn/8bd3a307009e7beea5081e8f1cbde13e to your computer and use it in GitHub Desktop.

Select an option

Save aspschn/8bd3a307009e7beea5081e8f1cbde13e to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <functional>
#include <type_traits>
#include <vector>
class ConnectionBase;
class SignalBase
{
public:
virtual void disconnect(ConnectionBase& connection)
{
}
};
class ConnectionBase
{
public:
virtual SignalBase* signal()
{
return nullptr;
}
private:
virtual void disconnect()
{
}
// virtual bool operator==(const ConnectionBase& foo);
};
template <typename... Args>
class Signal: public SignalBase
{
public:
class Connection: public ConnectionBase
{
friend Signal;
public:
Connection()
{
this->_signal = nullptr;
}
Connection(Signal<Args...> *signal, std::function<void(Args...)>& method)
{
this->_signal = signal;
this->_method = method;
}
SignalBase* signal()
{
return this->_signal;
}
bool operator==(const ConnectionBase& other)
{
return false;
}
private:
void call(Args... args)
{
this->_method(args...);
}
void disconnect()
{
this->_signal = nullptr;
}
private:
Signal<Args...> *_signal;
std::function<void(Args...)> _method;
};
public:
void emit(Args... args)
{
for (int i = 0; i < this->_connections.size(); ++i) {
this->_connections[i].call(args...);
}
}
template <typename T, typename Child>
Connection connect(T *receiver, void(Child::* slot)(Args...))
{
auto f = [receiver, slot](Args... args) {
(receiver->*slot)(std::forward<Args>(args)...);
};
// this->_connections.push_back(f);
// this->_connections.push_back(Connection(this, f));
return this->connect(f);
}
Connection connect(std::function<void(Args...)> slot)
{
// this->_connections.push_back(slot);
auto connection = Connection(this, slot);
this->_connections.push_back(connection);
return connection;
}
void disconnect(Connection &connection)
{
auto begin = this->_connections.begin();
auto end = this->_connections.end();
for (auto it = begin; it != end; ++it) {
if (*it == connection) {
connection.disconnect();
this->_connections.erase(it);
break;
}
}
}
private:
// std::vector<std::function<void(Args...)>> _connections;
std::vector<Connection> _connections;
};
class Widget
{
public:
template <typename... Args, typename SignalType, typename Functor>
static auto connect(SignalType signal,
Widget *receiver, Functor method)
{
return signal->connect(method);
}
template <typename... Args, typename SignalType, typename Child>
static auto connect(SignalType signal,
Child *receiver, void (Child::* method)(Args...))
{
static_assert(std::is_base_of<Widget, Child>::value == true, "TEST");
return signal->connect(receiver, method);
}
template <typename... Args>
//static void disconnect(typename Signal<Args...>::Connection& connection)
static void disconnect(ConnectionBase& connection)
{
// connection.disconnect();
connection.signal()->disconnect(connection);
}
};
class Button : public Widget
{
public:
Signal<int> click;
public:
void conn()
{
Widget::connect(&this->click, this, [](int a) {
printf("A lambda slot: %d\n", a);
});
Widget::connect(&this->click, this, &Button::test_slot);
}
void test_slot(int a)
{
printf("A test slot: %d\n", a);
}
void simulate_click()
{
this->click.emit(42);
}
void disconn()
{
Widget::disconnect(this->click_connection2);
}
private:
decltype(click)::Connection click_connection1;
decltype(click)::Connection click_connection2;
};
class PushButton : public Button
{
public:
Signal<int> click;
public:
void conn()
{
Widget::connect(&this->click, this, [](int b) {
printf("PushButton lambda slot: %d\n", b);
});
}
};
int main(int argc, char *argv[])
{
Button button = Button();
button.conn();
button.simulate_click();
PushButton push_button = PushButton();
button.conn();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment