#pragma once #include #include //This header simply declares the signature for the callback expected when a NetMsg arrives after a user //registers via: //template< typename NetMsgT > //void GLView::subscribe_NetMsg_to_callback( callback_on_NetMsgT_arrived func ); namespace Aftr { class NetMsg; template< class NetMsgT > using callback_on_NetMsgT_arrived = std::function< void( std::unique_ptr< NetMsgT > ) >; struct callback_NetMsgT_erased { template< typename NetMsgT > callback_NetMsgT_erased( callback_on_NetMsgT_arrived func, unsigned int NetMsgID ) : NetMsgID( NetMsgID ) { this->pimpl = std::make_shared< callback_concrete >( std::forward >( func ) ); } //Always returns true if the functor/callback was invoked, returns false if the functor did not exist / was not called bool operator()( NetMsg* msg ) { if( pimpl ) { //we know that msg is actually of subclass NetMsgID-type, so cast and invoke callback this->pimpl->invoke( msg ); return true; } return false; } unsigned int NetMsgID = -1; private: //Use type erasure to hide the templated type and only retrieve that type //at the instant the callback needs to be invoked. struct callback_abstract { virtual ~callback_abstract() = default; virtual void invoke( NetMsg* msg ) = 0; }; template< typename NetMsgT > struct callback_concrete : callback_abstract { explicit callback_concrete( callback_on_NetMsgT_arrived func ) : functor(func) { } virtual void invoke( NetMsg* msg ) override { //Right here we know the TEMPLATED type AND has a pointer to the NetMsg. //So we can do the magic right here, right now! NetMsgT* subclass = static_cast(msg); std::unique_ptr< NetMsgT > ptr( subclass ); //ptr takes full ownership of NetMsg this->functor( std::move(ptr) ); } callback_on_NetMsgT_arrived functor; }; std::shared_ptr< callback_abstract > pimpl; }; }