Hello !
Voilà, je me suis lancé dans la conception d'une classe de signaux (style signaux/slots) simpliste en C++11 mais ne demandant qu'à évoluer, concrètement voici où j'en suis:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | template<typename... Args> class NzSignal { public: using Callback = std::function<void(Args...)>; NzSignal() = default; ~NzSignal() = default; void Connect(const Callback& func); void Connect(Callback&& func); template<typename O> void Connect(O& object, void (O::*method)(Args...)); template<typename O> void Connect(O* object, void (O::*method)(Args...)); void operator()(Args&&... args); private: std::vector<Callback> m_callbacks; }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | template<typename... Args> void NzSignal<Args...>::Connect(const Callback& func) { m_callbacks.push_back(func); } template<typename... Args> void NzSignal<Args...>::Connect(Callback&& func) { m_callbacks.emplace_back(std::move(func)); } template<typename... Args> template<typename O> void NzSignal<Args...>::Connect(O& object, void (O::*method) (Args...)) { return Connect([&object, method] (Args&&... args) { return (object .* method) (std::forward<Args>(args)...); }); } template<typename... Args> template<typename O> void NzSignal<Args...>::Connect(O* object, void (O::*method)(Args...)) { return Connect([object, method] (Args&&... args) { return (object ->* method) (std::forward<Args>(args)...); }); } template<typename... Args> void NzSignal<Args...>::operator()(Args&&... args) { for (const Callback& func : m_callbacks) func(std::forward<Args>(args)...); } |
Soit une implémentation extrêmement simpliste ne manquant fondamentalement que d'une chose: le support de la déconnexion.
Pour ce faire, je souhaiterai que ma méthode fonction membre Connect renvoie un objet du style "Connection", un objet représentant donc très simplement le lien entre le signal et le slot. L'objectif est ensuite de disposer d'un objet ScopedConnection me permettant d'utiliser le RRID (Resource Release Is Destruction, un nom que je préfère à RAII).
Bien entendu, cette interface est très inspirée de celle de Boost, que je n'utilise pas pour ses interdépendances et sa lourdeur (ne serait-ce qu'au niveau de la compilation), ce point a déjà été largement discuté, ce sujet n'est pas là pour ça.
Mon problème c'est que je n'ai aucune idée de comment procéder à l'implémentation, je ne suis pas très familier avec l'utilisation poussée des templates, et ici je ne sais vraiment pas comment je suis censé faire le lien entre un objet Connection (pouvant être copié), un objet Signal template et un accès aux callbacks (pour les identifier).
Mon objectif est que cette classe soit performante surtout au niveau du signalement, étant donné qu'elle risque d'être utilisée à des endroits un minimum critiques de mon moteur.
Notez bien qu'ici je ne demande pas forcément de solution toute faite, tout au plus des pistes de réflexion
En vous remerciant !