{"id":289982,"date":"2018-09-27T13:15:02","date_gmt":"2018-09-27T09:15:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=289982"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=289982","title":{"rendered":"C++11 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439"},"content":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\u0414\u0443\u043c\u0430\u044e, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043a\u0430\u043a \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u041e\u041e\u041f, \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u043f\u043e\u0447\u0442\u0438 \u043a\u0430\u0436\u0434\u043e\u043c\u0443, \u043a\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0445\u043e\u0442\u044c \u0440\u0430\u0437 \u043a\u0430\u0441\u0430\u043b\u0441\u044f \u041e\u041e\u041f. \u041f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0435 \u043c\u0435\u0440\u0435, \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432\u0435\u0441\u044c\u043c\u0430 \u0443\u0434\u043e\u0431\u0435\u043d \u0432 \u0432\u0435\u0441\u044c\u043c\u0430 \u0448\u0438\u0440\u043e\u043a\u043e\u043c, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0441\u043f\u0435\u043a\u0442\u0440\u0435 \u0437\u0430\u0434\u0430\u0447. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c; \u043e\u0434\u043d\u0430\u043a\u043e \u0432 C++ \u0442\u0430\u043a\u043e\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u043d\u0435\u0442. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441 \u044d\u0442\u0438\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c.<br \/>  <a name=\"habracut\"><\/a><br \/>  <a name=\"Intro\"><\/a><\/p>\n<h1>\u041a\u0440\u0430\u0442\u043a\u043e\u0435 \u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435<\/h1>\n<p>  <i>\u0421\u043e\u0431\u044b\u0442\u0438\u0435<\/i> \u2014 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u043f\u0440\u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u043d\u0430 \u043d\u0435\u0451 \u043c\u044b\u0448\u043a\u043e\u0439). \u0414\u0440\u0443\u0433\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u043d\u0430\u0442\u044c \u043e\u0431 \u044d\u0442\u043e\u043c; \u0442\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 <i>\u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435<\/i>. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <i>\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a<\/i> \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0433\u043e \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430; \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443 \u043d\u0435\u0433\u043e \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u0434, \u0442.\u0435. \u043e\u0442\u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435. \u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e, \u043e\u0431\u044a\u0435\u043a\u0442 \u043c\u043e\u0436\u0435\u0442 <i>\u043e\u0442\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f \u043e\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/i>, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0445\u043e\u0447\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u043d\u0430 \u043d\u0435\u0433\u043e \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u0438\u043c\u0435\u0435\u043c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0434\u0440\u0443\u0433 \u0441 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043e\u0434\u043d\u0438\u0445 \u0438\u0437 \u043d\u0438\u0445 \u0438 \u0440\u0435\u0430\u043a\u0446\u0438\u0438 \u043d\u0430 \u044d\u0442\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u0445.<br \/>  \u041a\u0430\u043a-\u0442\u043e \u0442\u0430\u043a, \u0445\u043e\u0442\u044f \u044d\u0442\u043e \u0438 \u0442\u0430\u043a \u0432\u0441\u0435 \u0437\u043d\u0430\u044e\u0442.<\/p>\n<p>  <a name=\"Trivial\"><\/a><\/p>\n<h1>\u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/h1>\n<p>  \u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e. \u0418 \u044d\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0442\u0430\u043a:  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class AbstractEventHandler {     public:         virtual void call( TParams... params ) = 0;     protected:             AbstractEventHandler() {} }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class TEvent {     using TEventHandler = AbstractEventHandler&lt;TParams...&gt;;     public:         TEvent() :             m_handlers()         {         }         ~TEvent()         {             for( TEventHandler* oneHandler : m_handlers )                 delete oneHandler;             m_handlers.clear();         }         void operator()( TParams... params )         {             for( TEventHandler* oneHandler : m_handlers )                 oneHandler-&gt;call( params... );         }         void operator+=( TEventHandler& eventHandler )         {             m_handlers.push_back( &eventHandler );         }     private:         std::list&lt;TEventHandler*&gt; m_handlers; }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TObject, class ...TParams&gt; class MethodEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     using TMethod = void( TObject::* )( TParams... );     public:         MethodEventHandler( TObject& object, TMethod method ) :             AbstractEventHandler&lt;TParams...&gt;(),             m_object( object ),             m_method( method )         {             assert( m_method != nullptr );         }         virtual void call( TParams... params ) override final         {             ( m_object.*m_method )( params... );         }     private:         TObject& m_object;         TMethod m_method; };  template&lt;class TObject, class ...TParams&gt; AbstractEventHandler&lt;TParams...&gt;& createMethodEventHandler( TObject& object, void( TObject::*method )( TParams... ) ) {     return *new MethodEventHandler&lt;TObject, TParams...&gt;( object, method ); }  #define METHOD_HANDLER( Object, Method ) createMethodEventHandler( Object, &Method ) #define MY_METHOD_HANDLER( Method ) METHOD_HANDLER( *this, Method ) <\/code><\/pre>\n<p>  \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430 \u0434\u043e\u043b\u0436\u043d\u043e \u0438\u043c\u0435\u0442\u044c \u0432\u0438\u0434:  <\/p>\n<pre><code class=\"cpp\">class TestWindow {     . . .     public:         TEvent&lt;const std::string&, unsigned int&gt; onButtonClick;     . . . }; class ClickEventHandler {     . . .     public:         void testWindowButtonClick( const std::string&, unsigned int ) { ... }     . . . }; int main( int argc, char *argv[] ) {     . . .     TestWindow testWindow;     ClickEventHandler clickEventHandler;      testWindow.onButtonClick += METHOD_HANDLER( clickEventHandler, ClickEventHandler::testWindowButtonClick );     . . . } <\/code><\/pre>\n<p>  \u0415\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a-\u043c\u0435\u0442\u043e\u0434 (-\u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0447\u043b\u0435\u043d \u043a\u043b\u0430\u0441\u0441\u0430) \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0436\u0435.<br \/>  \u041a\u0430\u0436\u0435\u0442\u0441\u044f, \u0432\u0441\u0451 \u0443\u0434\u043e\u0431\u043d\u043e, \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u043e \u0438 \u0437\u0434\u043e\u0440\u043e\u0432\u043e. \u041d\u043e \u043f\u043e\u043a\u0430 \u0435\u0441\u0442\u044c \u0440\u044f\u0434 \u043d\u0435\u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043e\u043a.<\/p>\n<p>  <a name=\"HandlerCompare\"><\/a><\/p>\n<h1>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432<\/h1>\n<p>  \u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043f\u0438\u0441\u043a\u0443 \u043e\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f (\u043d\u0430 <i>==<\/i> \u0438 <i>!==<\/i>). \u0420\u0430\u0432\u043d\u044b\u043c\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u0442\u0430\u043a\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043c\u0435\u0442\u043e\u0434 (-\u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0447\u043b\u0435\u043d \u043a\u043b\u0430\u0441\u0441\u0430) \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 (\u0442.\u0435. \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u043a\u043b\u0430\u0441\u0441\u0430).  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class AbstractEventHandler {     . . .     using MyType = AbstractEventHandler&lt;TParams...&gt;;     public:         bool operator==( const MyType& other ) const         {             return isEquals( other );         }         bool operator!=( const MyType& other ) const         {             return !( *this == other );         }     protected:         virtual bool isEquals( const MyType& other ) const = 0;     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TMethodHolder, class ...TParams&gt; class MethodEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     . . .     using TMethod = void( TObject::* )( TParams... );     protected:         virtual bool isEquals( const AbstractEventHandler&lt;TParams...&gt;& other ) const override         {             const MyType* _other = dynamic_cast&lt;const MyType*&gt;( &other );             return ( _other != nullptr && &m_object == &_other.m_object && m_method == _other.m_method );         }     private:         TObject& m_object;         TMethod m_method;     . . . }; <\/code><\/pre>\n<p>  \u0422\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0438\u0437 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0412 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 (\u0440\u0430\u0432\u043d\u044b\u0435) \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438.  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class TEvent {     . . .     using TEventHandler = AbstractEventHandler&lt;TParams...&gt;;     using TEventHandlerIt = typename std::list&lt;TEventHandler*&gt;::const_iterator;     public:         bool operator+=( TEventHandler& eventHandler )         {             if( findEventHandler( eventHandler ) == m_handlers.end() )             {                 m_handlers.push_back( &eventHandler );                 return true;             }             return false;         }         bool operator-=( TEventHandler& eventHandler )         {             auto it = findEventHandler( eventHandler );             if( it != m_handlers.end() )             {                 TEventHandler* removedEventHandler = *it;                 m_handlers.erase( it );                 delete removedEventHandler;                 return true;             }             return false;         }     private:         inline TEventHandlerIt findEventHandler( TEventHandler& eventHandler ) const         {             return std::find_if( m_handlers.cbegin(), m_handlers.cend(), [ &eventHandler ]( const TEventHandler* oneHandler )             {                 return ( *oneHandler == eventHandler );             } );         }         std::list&lt;TEventHandler*&gt; m_handlers;     . . . }; <\/code><\/pre>\n<p>  \u0417\u0434\u0435\u0441\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 <i>true<\/i> \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0438 <i>false<\/i>, \u0435\u0441\u043b\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 (\u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435) \u043d\u0435 \u0431\u044b\u043b\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043e.<br \/>  \u0414\u0430, \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u043d\u0438\u043a\u0443\u0434\u0430 \u043d\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0438\u0433\u0434\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u044e\u0442\u0441\u044f. \u041d\u043e \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0436\u0435.<br \/>  \u041c\u043e\u0436\u043d\u043e \u043b\u0438 \u044d\u0442\u0438\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f? \u041f\u043e\u043a\u0430 \u0435\u0449\u0451 \u043d\u0435 \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u043c\u0435\u0440\u0435.<\/p>\n<p>  <a name=\"HandlerRemoving\"><\/a><\/p>\n<h1>\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430<\/h1>\n<p>  \u0418\u0442\u0430\u043a, \u0441\u0440\u0430\u0437\u0443 \u0436\u0435 \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0441 \u043f\u0430\u0434\u0435\u043d\u0438\u0435\u043c \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u0434\u0430, \u0433\u0434\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0430\u043c \u043e\u0442\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0441\u0435\u0431\u044f \u043e\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u0434\u0443\u043c\u0430\u044e, \u043d\u0435 \u0441\u0430\u043c\u044b\u0439 \u0440\u0435\u0434\u043a\u0438\u0439 <i>use case<\/i>, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0441\u0430\u043c\u043e\u0432\u044b\u043f\u0438\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445):  <\/p>\n<pre><code class=\"cpp\">class TestWindow {     . . .     public:         TEvent&lt;const std::string&, unsigned int&gt; onButtonClick;         static TestWindow& instance();     . . . }; class ClickEventHandler {     . . .     public:         void testWindowButtonClick( const std::string&, unsigned int )         {             TestWindow::instance().onButtonClick -= MY_METHOD_HANDLER( ClickEventHandler::testWindowButtonClick );         }     . . . }; int main( int argc, char *argv[] ) {     . . .     ClickEventHandler clickEventHandler;     TestWindow::instance().onButtonClick += METHOD_HANDLER( clickEventHandler, ClickEventHandler::testWindowButtonClick );     . . . } <\/code><\/pre>\n<p>  \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043f\u043e \u0432\u0435\u0441\u044c\u043c\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u0440\u0438\u0447\u0438\u043d\u0435:<\/p>\n<ul>\n<li>\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043f\u0435\u0440\u0435\u0431\u0438\u0440\u0430\u0442\u044c (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432) \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438, \u0432\u044b\u0437\u044b\u0432\u0430\u044f \u0438\u0445;<\/li>\n<li>\u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u0441\u0435\u0431\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0431\u044f;<\/li>\n<li>\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a, \u0434\u0435\u043b\u0430\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0435\u043c\u0443 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c;<\/li>\n<li>\u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043a \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0443 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445, \u043e\u0434\u043d\u0430\u043a\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440 (\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443) \u0443\u0436\u0435 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u0435\u043d;<\/li>\n<li>\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e\u043c\u0443 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u0443, \u0432\u044b\u0437\u044b\u0432\u0430\u044f \u043f\u0430\u0434\u0435\u043d\u0438\u0435.<\/li>\n<\/ul>\n<p>  \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0438, \u043a\u043e\u0433\u0434\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0451\u043d, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u043b\u0438 \u0431\u044b \u043a \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u0438 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432; \u0438 \u0437\u0430\u0442\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0449\u0438\u0442\u0443 \u043e\u0442 \u0447\u0442\u0435\u043d\u0438\u044f \u0442\u0430\u043a\u0438\u0445 \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432.<br \/>  \u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u043c <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/container\/list\">std::list<\/a>&#8216;\u0430 \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u0442 \u0444\u0430\u043a\u0442, \u0447\u0442\u043e \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u043e\u043d \u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440 \u2014 \u043d\u0430 \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 (\u043d\u0430 \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435); \u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439: \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u043c \u0432 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432. \u0412 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u043e\u0436\u043d\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043f\u043e\u0434\u043b\u0435\u0436\u0438\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044e, \u0438 \u043f\u0443\u0441\u0442\u044c \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.<br \/>  \u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u0440\u0430\u0437\u0443 \u0432\u043a\u0430\u0442\u0438\u0442\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u044d\u0442\u043e\u0433\u043e, \u043d\u043e \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439.<\/p>\n<p>  <a name=\"ThreadSafety\"><\/a><\/p>\n<h1>\u041f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c<\/h1>\n<p>  \u041f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e, \u0432\u044b\u0437\u043e\u0432\u044b \u0442\u0440\u0451\u0445 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u2014 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f, \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0438 \u043f\u0435\u0440\u0435\u0431\u043e\u0440\u0430 (\u043f\u0440\u0438 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f) \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u2014 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u043e\u0432 \u0432 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0446\u0435\u043b\u043e\u0435 \u043f\u043e\u043b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u043f\u043e \u0438\u0445 \u00ab\u043f\u0435\u0440\u0435\u0441\u0435\u0447\u0435\u043d\u0438\u044e\u00bb \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u00ab\u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u043d\u0438\u044e\u00bb \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430 \u0438 \u043f\u0430\u0434\u0435\u043d\u0438\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432 \u0438\u0442\u043e\u0433\u0435. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u044d\u0442\u043e\u0433\u043e; <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/thread\">\u043c\u044c\u044e\u0442\u0435\u043a\u0441\u044b \u2014 \u043d\u0430\u0448\u0435 \u0432\u0441\u0451<\/a>.  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class TEvent {     using TEventHandler = AbstractEventHandler&lt;TParams...&gt;;     using TEventHandlerIt = typename std::list&lt;TEventHandler*&gt;::const_iterator;     public:         TEvent() :             m_handlers(),             m_currentIt(),             m_isCurrentItRemoved( false ),             m_handlerListMutex()         {         }         void operator()( TParams... params )         {             m_handlerListMutex.lock_shared();                          m_isCurrentItRemoved = false;             m_currentIt = m_handlers.begin();             while( m_currentIt != m_handlers.end() )             {                 m_handlerListMutex.unlock_shared();                 ( *m_currentIt )-&gt;call( params... );                 m_handlerListMutex.lock_shared();                  if( m_isCurrentItRemoved )                 {                     m_isCurrentItRemoved = false;                      TEventHandlerIt removedIt = m_currentIt;                     ++m_currentIt;                      deleteHandler( removedIt );                 }                 else                 {                     ++m_currentIt;                 }             }              m_handlerListMutex.unlock_shared();         }         bool operator+=( TEventHandler& eventHandler )         {             std::unique_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );              if( findEventHandler( eventHandler ) == m_handlers.end() )             {                 m_handlers.push_back( std::move( eventHandler ) );                 return true;             }             return false;         }         bool operator-=( TEventHandler& eventHandler )         {             std::unique_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );              auto it = findEventHandler( eventHandler );             if( it != m_handlers.end() )             {                 if( it == m_currentIt )                     m_isCurrentItRemoved = true;                 else                     deleteHandler( it );                  return true;             }             return false;         }     private:               \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f 'm_handlerListMutex'         inline TEventHandlerIt findEventHandler( TEventHandler& eventHandler ) const         {             return std::find_if( m_handlers.cbegin(), m_handlers.cend(), [ &eventHandler ]( const TEventHandler* oneHandler )             {                 return ( *oneHandler == eventHandler );             } );         }         \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 'm_handlerListMutex'         inline void deleteHandler( TEventHandlerIt it )         {             TEventHandler* removedEventHandler = *it;             m_handlers.erase( it );             delete removedEventHandler;         }                  std::list&lt;TEventHandler*&gt; m_handlers;          \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c 'm_handlerListMutex'         mutable TEventHandlerIt m_currentIt;         mutable bool m_isCurrentItRemoved;          mutable std::shared_mutex m_handlerListMutex; }; <\/code><\/pre>\n<p>  \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u00ab\u043e\u043a\u043d\u043e\u00bb \u043d\u0435\u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u043e\u0447\u0442\u0438 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430. \u042d\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0442\u0435\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044e \u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\/\u0443\u0434\u0430\u043b\u044f\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438), \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u044f <a href=\"https:\/\/ru.wikipedia.org\/wiki\/\u0412\u0437\u0430\u0438\u043c\u043d\u0430\u044f_\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u043a\u0430\">deadlock<\/a>. \u0417\u0430 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u043e\u043f\u0430\u0441\u0430\u0442\u044c\u0441\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e, \u043a\u0430\u043a \u043c\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u0438, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u043a \u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u2014 \u044d\u0442\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430, \u0430 \u0434\u0430\u043d\u043d\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u0430.<\/p>\n<p>  <a name=\"EventVisibility\"><\/a><\/p>\n<h1>\u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f<\/h1>\n<p>  \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0447\u043b\u0435\u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0435\u0433\u043e \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c <i>public<\/i>, \u0447\u0442\u043e\u0431\u044b \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043c\u043e\u0433\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\/\u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e <i>operator()<\/i>, \u0442.\u0435. \u0432\u044b\u0437\u043e\u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0442\u043e\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u0437\u0432\u043d\u0435, \u0447\u0442\u043e \u0432 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u043e. \u0420\u0435\u0448\u0438\u043c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u0438\u0437 \u043a\u043b\u0430\u0441\u0441\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (<i>TEvent&lt;&#8230;&gt;<\/i>) \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043e\u043f\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438.  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class IEvent {     protected:         using TEventHandler = AbstractEventHandler&lt;TParams...&gt;;     public:         bool operator+=( TEventHandler& eventHandler )         {            return addHandler( eventHandler );         }         bool operator-=( TEventHandler& eventHandler )         {             return removeHandler( eventHandler );         }     protected:         IEvent() {}         virtual bool addHandler( TEventHandler& eventHandler ) = 0;         virtual bool removeHandler( TEventHandler& eventHandler ) = 0; }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class TEvent : public IEvent&lt;TParams...&gt; {     . . .     public:         TEvent() :             IEvent&lt;TParams...&gt;()             . . .         {         }     protected:         virtual bool addHandler( TEventHandler& eventHandler ) override         {             \/\/ \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0440\u0430\u043d\u0435\u0435 \u0432 'TEvent::operator+='         }         virtual bool removeHandler( TEventHandler& eventHandler ) override         {             \/\/ \u043a\u043e\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b\u043b \u0440\u0430\u043d\u0435\u0435 \u0432 'TEvent::operator-='         }     . . . }; <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0437\u043d\u0435\u0441\u0442\u0438 \u0432 \u0440\u0430\u0437\u043d\u044b\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0447\u0430\u0441\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0430\u044f \u0437\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438, \u0438 \u0447\u0430\u0441\u0442\u044c, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0443\u044e \u0437\u0430 \u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432.  <\/p>\n<pre><code class=\"cpp\">class TestWindow {     . . .     public:         TestWindow() :             onButtonClick( m_onButtonClick ),             m_onButtonClick()         {         }         IEvent&lt;const std::string&, unsigned int&gt;& onButtonClick;     protected:         TEvent&lt;const std::string&, unsigned int&gt; m_onButtonClick;     . . . }; <\/code><\/pre>\n<p>  \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0442\u0435\u043f\u0435\u0440\u044c \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\/\u0443\u0434\u0430\u043b\u044f\u0442\u044c \u0441\u0432\u043e\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 <i>TestWindow::onButtonClick<\/i>, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0441\u043c\u043e\u0433\u0443\u0442 \u0441\u0430\u043c\u0438 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435. \u0412\u044b\u0437\u043e\u0432 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 <i>TestWindow<\/i> (\u0438 \u0435\u0433\u043e \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432, \u0435\u0441\u043b\u0438 \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043a\u0430\u043a \u043f\u0440\u0438\u043c\u0435\u0440\u0435, <i>protected<\/i>).<br \/>  \u0422\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u043e\u043d\u0435\u043c\u043d\u043e\u0433\u0443 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432 \u043d\u0435\u0447\u0442\u043e \u043c\u043e\u043d\u0441\u0442\u0440\u0443\u043e\u0437\u043d\u043e\u0435, \u043d\u043e \u044d\u0442\u043e \u0435\u0449\u0451 \u043d\u0435 \u043a\u043e\u043d\u0435\u0446.<\/p>\n<p>  <a name=\"EventHandlerParams\"><\/a><\/p>\n<h1>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432<\/h1>\n<p>  \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0438 \u043b\u044e\u0431\u043e\u0439 \u0435\u0451 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u043c\u0435\u0442\u044c \u0441\u0442\u0440\u043e\u0433\u043e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432. \u042d\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0440\u044f\u0434\u0443 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u0432.<br \/>  <b>\u041f\u0435\u0440\u0432\u043e\u0435.<\/b> \u041f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d \u043a\u043b\u0430\u0441\u0441\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u043c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c.  <\/p>\n<pre><code class=\"cpp\">template&lt;class TSource&gt; class MyClass {     . . .     public:         TEvent&lt;const TSource&&gt; onValueChanged;     . . . }; <\/code><\/pre>\n<p>  \u0412\u0432\u0438\u0434\u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0442\u0438\u043f, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0437\u0434\u0435\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d, \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d, \u0435\u0441\u0442\u044c \u0441\u043c\u044b\u0441\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043f\u043e \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0435, \u0430 \u043d\u0435 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e. \u041e\u0434\u043d\u0430\u043a\u043e \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0439 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u0434\u0430\u0436\u0435 \u0441 \u0444\u0443\u043d\u0434\u0430\u043c\u0435\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438, \u043e\u0431\u044f\u0437\u0430\u043d\u044b \u0431\u044b\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438.  <\/p>\n<pre><code class=\"cpp\">MyClass&lt;bool&gt; myBoolClass; . . . template&lt;class TSource&gt; class MyHandlerClass {     . . .     private:         void handleValueChanged1( const bool& newValue );         void handleValueChanged2( bool newValue );     . . . }; . . . MyHandlerClass myHandlerClass; myBoolClass.onValueChanged += METHOD_HANDLER( myHandlerClass, MyHandlerClass::handleValueChanged1 );  \/\/ OK myBoolClass.onValueChanged += METHOD_HANDLER( myHandlerClass, MyHandlerClass::handleValueChanged2 );  \/\/ compile error <\/code><\/pre>\n<p>  \u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0441 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435\u043c \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 \u0432\u0438\u0434\u0430 <i>MyHandlerClass::handleValueChanged2<\/i>, \u043d\u043e \u043f\u043e\u043a\u0430 \u0442\u0430\u043a\u043e\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043d\u0435\u0442.<br \/>  <b>\u0412\u0442\u043e\u0440\u043e\u0435.<\/b> \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a-\u0444\u0443\u043d\u043a\u0442\u043e\u0440 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0435\u043c\u0443\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0443-\u043c\u0435\u0442\u043e\u0434\u0443 (-\u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0447\u043b\u0435\u043d\u0443 \u043a\u043b\u0430\u0441\u0441\u0430).  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor, class ...TParams&gt; class FunctorEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     public:         FunctorEventHandler( TFunctor& functor ) :             AbstractEventHandler&lt;TParams...&gt;(),             m_functor( functor )         {         }         virtual void call( TParams... params ) override final         {             m_functor( params... );         }     private:         TFunctor& m_functor; };  template&lt;class TFunctor, class ...TParams&gt; AbstractEventHandler&lt;TParams...&gt;& createFunctorEventHandler( TFunctor&& functor ) {     return *new FunctorEventHandler&lt;TFunctor, TParams...&gt;( functor ); }  #define FUNCTOR_HANDLER( Functor ) createFunctorEventHandler( Functor ) <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u0440\u0438\u0432\u0438\u043d\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u043a \u043a\u0430\u043a\u043e\u043c\u0443-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044e.  <\/p>\n<pre><code class=\"cpp\">class TestWindow {     . . .     public:         TEvent&lt;const std::string&, unsigned int&gt; onButtonClick;     . . . }; struct ClickEventHandler {     void operator()( const std::string&, unsigned int ) { . . . } }; int main( int argc, char *argv[] ) {     . . .     TestWindow testWindow;     ClickEventHandler clickEventHandler;      testWindow.onButtonClick += FUNCTOR_HANDLER( clickEventHandler );     . . . } <\/code><\/pre>\n<p>  \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438. \u0414\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <i>createFunctorEventHandler<\/i> \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0442\u0438\u043f\u044b <i>TParams&#8230;<\/i> \u0438\u0437 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u2014 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430. \u0424\u0443\u043d\u043a\u0442\u043e\u0440 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0442\u043e\u043c, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u0430\u043a\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435. \u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438 \u2014 \u044d\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435:  <\/p>\n<pre><code class=\"cpp\">testWindow.onButtonClick += createFunctorEventHandler&lt;ClickEventHandler, const std::string&, unsigned int&gt;( clickEventHandler ); <\/code><\/pre>\n<p>  \u041d\u043e \u0432\u0435\u0434\u044c \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0432\u0441\u0435\u043c \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f.<\/p>\n<p>  <a name=\"HandlerHolder\"><\/a><\/p>\n<h1>\u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432<\/h1>\n<p>  \u0418\u0442\u0430\u043a, \u0445\u043e\u0442\u0435\u043b\u043a\u0430 \u0435\u0441\u0442\u044c, \u0434\u0435\u043b\u043e \u0437\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439. \u0411\u0443\u0434\u0435\u043c \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0442\u044c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a-\u043c\u0435\u0442\u043e\u0434 (-\u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0447\u043b\u0435\u043d \u043a\u043b\u0430\u0441\u0441\u0430) \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<br \/>  \u0420\u0430\u0437 \u0443\u0436 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u043b\u0438\u0448\u044c \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0435\u043c\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0442\u043e \u0438 \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u043c \u044d\u0442\u043e\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c. \u0410\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u0435 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0435\u0433\u043e \u043a \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044e. \u0418 \u0434\u0430, \u044d\u0442\u043e \u0434\u0432\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u0430. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u0438\u0434\u0435\u044e \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor&gt; class FunctorHolder;  template&lt;class TFunctor, class ...TParams&gt; class FunctorEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     public:         FunctorEventHandler( FunctorHolder&lt;TFunctor&gt;& functorHolder ) :             AbstractEventHandler&lt;TParams...&gt;(),             m_functorHolder( functorHolder )         {         }         virtual void call( TParams... params ) override         {             m_functorHolder.m_functor( params... );         }         private:         FunctorHolder&lt;TFunctor&gt;& m_functorHolder;     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor&gt; class FunctorHolder {     public:         FunctorHolder( TFunctor& functor ) :             m_functor( functor )         {         }         template&lt;class ...TCallParams&gt;         operator AbstractEventHandler&lt;TCallParams...&gt;&()         {             return *new FunctorEventHandler&lt;TFunctor, TCallParams...&gt;( *this );         }     private:         TFunctor& m_functor;     . . .     template&lt;class TFunctor, class ...TParams&gt; friend class FunctorEventHandler; }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor&gt; FunctorHolder&lt;TFunctor&gt;& createFunctorEventHandler( TFunctor&& functor ) {     return *new FunctorHolder&lt;TFunctor&gt;( functor ); }  #define     FUNCTOR_HANDLER( Functor )              createFunctorEventHandler( Functor ) #define     LAMBDA_HANDLER( Lambda )                FUNCTOR_HANDLER( Lambda ) #define     STD_FUNCTION_HANDLER( StdFunction )     FUNCTOR_HANDLER( StdFunction ) #define     FUNCTION_HANDLER( Function )            FUNCTOR_HANDLER( &Function ) <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class IEvent {     protected:         using TEventHandler = AbstractEventHandler&lt;TParams...&gt;;     public:         template&lt;class TSome&gt;         bool operator+=( TSome&& some )         {            return addHandler( static_cast&lt;TEventHandler&&gt;( some ) );         }         template&lt;class TSome&gt;         bool operator-=( TSome&& some )         {             return removeHandler( static_cast&lt;TEventHandler&&gt;( some ) );         }     protected:         IEvent() {}         virtual bool addHandler( TEventHandler& eventHandler ) = 0;         virtual bool removeHandler( TEventHandler& eventHandler ) = 0; }; <\/code><\/pre>\n<p>  \u0415\u0441\u043b\u0438 \u0432\u043a\u0440\u0430\u0442\u0446\u0435, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0438 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0435\u0433\u043e \u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044e \u0437\u0434\u0435\u0441\u044c \u0438\u043c\u0435\u0435\u0442 \u0431\u043e\u043b\u0435\u0435 \u044f\u0440\u043a\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u043d\u044b\u0439 \u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440, \u0447\u0435\u043c \u0440\u0430\u043d\u0435\u0435. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043e\u0431\u043e\u0439\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b, \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u043f\u0443\u043d\u043a\u0442\u0435. \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0438\u043f\u043e\u0432 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u043f\u0440\u0438\u043a\u0430\u0441\u0442\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0439 <i>FunctorHolder<\/i> \u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u043e\u043c\u0443 <i>FunctorEventHandler<\/i>, \u0430 \u0442\u043e\u0447\u043d\u0435\u0435, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <i>FunctorEventHandler&lt;.. .&gt;<\/i> \u0441 \u0432\u0435\u0441\u044c\u043c\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430; \u0438 \u0432 \u044d\u0442\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0442\u0440\u043e\u0447\u043a\u0430 \u043a\u043e\u0434\u0430 <i>m_functorHolder.m_functor( params\u2026 );<\/i>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0438\u043f\u043e\u0432, \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0445 \u0441 \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u043c (\u043b\u0438\u0431\u043e \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0444\u0443\u043d\u043a\u0442\u043e\u0440, \u0442.\u0435. \u043e\u0431\u044a\u0435\u043a\u0442, \u043d\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0439 <i>operator()<\/i>).<br \/>  \u041f\u043e\u0432\u0442\u043e\u0440\u044e\u0441\u044c, \u0447\u0442\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0430 \u043d\u0438\u0436\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u0443\u0447\u0430 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432 \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439 \u0441\u0434\u0435\u043b\u0430\u043d\u0430, \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0441 \u0446\u0435\u043b\u044c\u044e \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432, \u0430 \u0432\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u043d\u0430 \u0441\u043b\u0443\u0447\u0430\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0439 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430\u043f\u0438\u043b\u044c\u043d\u0438\u043a\u043e\u043c \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u0438\u0437 \u043d\u0438\u0445.<br \/>  \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.  <\/p>\n<pre><code class=\"cpp\">class TestWindow {     . . .     public:         TEvent&lt;const std::string&, unsigned int&gt; onButtonClick;     . . . }; struct Functor {     void operator()( const std::string&, unsigned int ) {} }; struct Functor2 {     void operator()( std::string, unsigned int ) {} }; struct Functor3 {     void operator()( const std::string&, const unsigned int& ) {} }; struct Functor4 {     void operator()( std::string, const unsigned int& ) {} }; struct Functor5 {     void operator()( std::string&, unsigned int& ) {} }; struct Functor6 {     void operator()( const std::string&, unsigned int& ) {} }; struct Functor7 {     void operator()( std::string&, const unsigned int& ) {} }; int main( int argc, char *argv[] ) {     . . .     TestWindow testWindow;          Functor functor;     Functor2 functor2;     Functor3 functor3;     Functor4 functor4;     Functor5 functor5;     Functor6 functor6;     Functor7 functor7;      testWindow.onButtonClick += FUNCTOR_HANDLER( functor );     \/\/ ok     testWindow.onButtonClick += FUNCTOR_HANDLER( functor2 );    \/\/ ok     testWindow.onButtonClick += FUNCTOR_HANDLER( functor3 );    \/\/ ok     testWindow.onButtonClick += FUNCTOR_HANDLER( functor4 );    \/\/ ok     testWindow.onButtonClick += FUNCTOR_HANDLER( functor5 );    \/\/ compile error     testWindow.onButtonClick += FUNCTOR_HANDLER( functor6 );    \/\/ ok     testWindow.onButtonClick += FUNCTOR_HANDLER( functor7 );    \/\/ compile error     . . . } <\/code><\/pre>\n<p>  \u041e\u0448\u0438\u0431\u043a\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u043f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0438\u0437 <i>const lvalue<\/i> \u0432 <i>lvalue<\/i>. \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0437 <i>rvalue<\/i> \u0432 <i>unconst lvalue<\/i> \u043e\u0448\u0438\u0431\u043a\u0438 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442, \u0445\u043e\u0442\u044f, \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u0443\u0433\u0440\u043e\u0437\u0443 \u0441\u0430\u043c\u043e\u0432\u044b\u0441\u0442\u0440\u0435\u043b\u0430 \u0432 \u043d\u043e\u0433\u0443: \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043d\u0430 \u0441\u0442\u0435\u043a \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0430\u0434\u043e\u0441\u0442\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u044b\u0445\u043e\u0434\u0435 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430.<br \/>  \u0412\u043e\u043e\u0431\u0449\u0435, \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code>Error\tC2664\t'void Functor5::operator ()(std::string &,unsigned int &)': cannot convert argument 1 from 'const std::string' to 'std::string &' <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0432 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u043c \u043a\u043e\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0449\u0451 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435. \u042d\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b (\u043f\u0440\u0438\u0437\u043d\u0430\u044e\u0441\u044c, \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u044f \u0433\u0434\u0435-\u0442\u043e \u043f\u043e\u0434\u0441\u043c\u043e\u0442\u0440\u0435\u043b):  <\/p>\n<pre><code class=\"cpp\">namespace {     template&lt;class TFunctor, class ...TParams&gt;     struct IsFunctorParamsCompatible     {         private:             template&lt;class TCheckedFunctor, class ...TCheckedParams&gt;             static constexpr std::true_type exists( decltype( std::declval&lt;TCheckedFunctor&gt;()( std::declval&lt;TCheckedParams&gt;()... ) )* = nullptr );                          template&lt;class TCheckedFunctor, class ...TCheckedParams&gt;             static constexpr std::false_type exists( ... );         public:             static constexpr bool value = decltype( exists&lt;TFunctor, TParams...&gt;( nullptr ) )::value;     }; } \/\/ <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor, class ...TParams&gt; class FunctorEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     . . .     public:         virtual void call( TParams... params ) override         {             static_assert( IsFunctorParamsCompatible&lt;TFunctor, TParams...&gt;::value, &quot;Event and functor arguments are not compatible&quot; );              m_functorHolder-&gt;m_functor( params... );         }     . . . }; <\/code><\/pre>\n<p>  <a name=\"AboutSfinae\"><\/a>\u0420\u0430\u0431\u043e\u0442\u0430 \u044d\u0442\u043e\u0442 \u0434\u0435\u043b\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0435 <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/sfinae\">SFINAE<\/a>. \u0412\u043a\u0440\u0430\u0442\u0446\u0435, \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u043f\u0435\u0440\u0432\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <i>exists<\/i>, \u043e\u0434\u043d\u0430\u043a\u043e, \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0435 \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 (\u043b\u0438\u0431\u043e \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f <i>operator()<\/i> \u0443 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430), \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043d\u0435 \u0432\u044b\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0442\u043e\u0440\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e; \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c \u0432\u0441\u0451, \u0447\u0442\u043e\u0431\u044b \u0435\u0451 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u044f \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043b\u0430 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u0441\u0435\u0433\u0434\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u043e \u0444\u0430\u043a\u0442\u0443 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u0430\u044f \u0436\u0435 \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0431\u044b\u043b\u0430 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0430, \u0434\u0435\u043b\u0430\u0435\u043c \u0432\u044b\u0432\u043e\u0434 (\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 <i>value<\/i>) \u043e \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432.<br \/>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:  <\/p>\n<pre><code class=\"cpp\">Error\tC2338\tEvent and functor arguments are not compatible Error\tC2664\t'void Functor5::operator ()(std::string &,unsigned int &)': cannot convert argument 1 from 'const std::string' to 'std::string &' <\/code><\/pre>\n<p>  \u041a\u0440\u043e\u043c\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0431\u043e\u043b\u0435\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0440\u0435\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430(\u043e\u0432) \u0438\u0437 <i>rvalue<\/i> \u0432 <i>unconst lvalue<\/i>: \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443 \u043d\u0435\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0442.\u0435. \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 <i>functor6<\/i> \u0438\u0437 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u044b\u0448\u0435 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043e\u0448\u0438\u0431\u043a\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438.<\/p>\n<p>  <a name=\"FunctorCompare\"><\/a><\/p>\n<h1>\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432<\/h1>\n<p>  \u0412\u0432\u0438\u0434\u0443 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430. \u0412\u043d\u043e\u0432\u044c \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a-\u043c\u0435\u0442\u043e\u0434 (-\u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0447\u043b\u0435\u043d \u043a\u043b\u0430\u0441\u0441\u0430) \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e.  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class AbstractEventHandler {     . . .     using MyType = AbstractEventHandler&lt;TParams...&gt;;     public:         bool operator==( const MyType& other ) const         {             return isEquals( other );         }         bool operator!=( const MyType& other ) const         {             return !( *this == other );         }     protected:         virtual bool isEquals( const MyType& other ) const = 0;     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor, class ...TParams&gt; class FunctorEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     . . .     using MyType = FunctorEventHandler&lt;TFunctor, TParams...&gt;;     protected:         virtual bool isEquals( const AbstractEventHandler&lt;TParams...&gt;& other ) const override         {             const MyType* _other = dynamic_cast&lt;const MyType*&gt;( &other );             return ( _other != nullptr && *m_functorHolder == *_other-&gt;m_functorHolder );         }     private:         FunctorHolder&lt;TFunctor&gt;& m_functorHolder;     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TFunctor&gt; class FunctorHolder {     . . .     using MyType = FunctorHolder&lt;TFunctor&gt;;     public:         bool operator==( const MyType& other ) const         {             return ( m_functor == other.m_functor );         }         bool operator!=( const MyType& other ) const         {             return !( *this == other );         }     private:         TFunctor& m_functor;     . . . }; <\/code><\/pre>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u0441\u0445\u043e\u0434\u0441\u0442\u0432\u0430 \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432.<br \/>  \u041a\u0430\u043a \u043e\u0442\u043c\u0435\u0447\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u0448\u0435, \u0443 \u043d\u0430\u0441 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0438\u043f\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432: \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u044b-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u044b, \u043b\u044f\u043c\u0431\u0434\u0430-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043a\u043b\u0430\u0441\u0441\u0430 <i>std::function<\/i>, \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u0418\u0437 \u043d\u0438\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u044b-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u044b, \u043b\u044f\u043c\u0431\u0434\u0430-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043a\u043b\u0430\u0441\u0441\u0430 <i>std::function<\/i> \u043d\u0435 \u043c\u043e\u0433\u0443\u0442 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <i>operator==<\/i> (\u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443), \u0430 \u0432\u043e\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0433\u0443\u0442, \u0442.\u043a. \u0443\u0436\u0435 \u0445\u0440\u0430\u043d\u044f\u0442\u0441\u044f \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u0443\u0447\u0430\u044f, \u0437\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0451 \u0432 \u043e\u0431\u0449\u0435\u043c \u0432\u0438\u0434\u0435:  <\/p>\n<pre><code class=\"cpp\">namespace {     template&lt;class TEqu, class TEnabled = void&gt;     struct EqualityChecker;      template&lt;class TEquatable&gt;     struct EqualityChecker&lt;TEquatable, typename std::enable_if&lt;is_equatable&lt;TEquatable&gt;::value&gt;::type&gt;     {         static constexpr bool isEquals( const TEquatable& operand1, const TEquatable& operand2 )         {             return ( operand1 == operand2 );         }     };      template&lt;class TNonEquatable&gt;     struct EqualityChecker&lt;TNonEquatable, typename std::enable_if&lt;!is_equatable&lt;TNonEquatable&gt;::value&gt;::type&gt;     {         static constexpr bool isEquals( const TNonEquatable& operand1, const TNonEquatable& operand2 )         {             return ( &operand1 == &operand2 );         }     }; } \/\/ template&lt;class TFunctor&gt; class FunctorHolder {     . . .     using MyType = FunctorHolder&lt;TFunctor&gt;;     public:         bool operator==( const MyType& other ) const         {             return EqualityChecker&lt;TFunctor&gt;::isEquals( m_functor, other.m_functor );         }     private:         TFunctor& m_functor;     . . . }; <\/code><\/pre>\n<p>  \u041f\u043e\u0434\u0440\u0430\u0437\u0443\u043c\u0435\u0432\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e <i>is_equatable<\/i> \u2014 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0438\u0439 \u043c\u043e\u0433\u0443\u0442 \u043b\u0438 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u044b \u043d\u0430 \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u043e \u0434\u0432\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430. \u0421 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/types\/enable_if\">std::enable_if<\/a>, \u043c\u044b \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0434\u0432\u0443\u0445 \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 <i>EqualityChecker<\/i>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435: \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0438\u043b\u0438 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d <i>is_equatable<\/i> \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code class=\"cpp\">template&lt;class T&gt; class is_equatable {     private:         template&lt;class U&gt;         static constexpr std::true_type exists( decltype( std::declval&lt;U&gt;() == std::declval&lt;U&gt;() )* = nullptr );          template&lt;class U&gt;         static constexpr std::false_type exists( ... );     public:         static constexpr bool value = decltype( exists&lt;T&gt;( nullptr ) )::value; }; <\/code><\/pre>\n<p>  \u0414\u0430\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0430 \u043d\u0430 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0435 <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/sfinae\">SFINAE<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0441\u044f <a href=\"#AboutSfinae\">\u0440\u0430\u043d\u0435\u0435<\/a>. \u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0434\u0435\u0441\u044c \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 <i>operator==<\/i> \u0434\u043b\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430.<br \/>  \u0422\u0430\u043a\u0438\u043c \u0432\u043e\u0442 \u043d\u0435\u0445\u0438\u0442\u0440\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432 \u0433\u043e\u0442\u043e\u0432\u0430.<\/p>\n<p>  <a name=\"GarbageCollection\"><\/a><\/p>\n<h1>\u0421\u0431\u043e\u0440\u043a\u0430 \u043c\u0443\u0441\u043e\u0440\u0430<\/h1>\n<p>  \u0411\u0443\u0434\u044c\u0442\u0435 \u0441\u043d\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u044b, \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0438 \u043c\u043d\u0435 \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0433\u0440\u043e\u043c\u043a\u0438\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a.<br \/>  \u041f\u0440\u0438\u0431\u043b\u0438\u0436\u0430\u0435\u043c\u0441\u044f \u043a \u0444\u0438\u043d\u0430\u043b\u0443, \u0438 \u043f\u043e\u0440\u0430 \u0443\u0436\u0435 \u0438\u0437\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043e\u0442 \u043e\u0433\u0440\u043e\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u0435\u0442.<br \/>  \u041f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0434\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430: <i>Holder<\/i>, \u0445\u0440\u0430\u043d\u044f\u0449\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0438 <i>EventHandler<\/i>, \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0435\u0433\u043e \u0441 \u0441\u043e\u0431\u044b\u0442\u0438\u0435\u043c. \u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u0435\u043c, \u0447\u0442\u043e \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u043f\u044b\u0442\u043a\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0438\u043a\u0430\u043a\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u2014 \u0434\u0432\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u00ab\u043f\u043e\u0432\u0438\u0441\u043b\u0438 \u0432 \u0432\u043e\u0437\u0434\u0443\u0445\u0435\u00bb (\u0435\u0441\u043b\u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u044d\u0442\u043e\u0442 \u0441\u043b\u0443\u0447\u0430\u0439 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437). \u0414\u0440\u0443\u0433\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f: \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430; \u0442\u0430\u043a \u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0442\u0430\u043a\u043e\u0433\u043e \u0436\u0435 (\u0440\u0430\u0432\u043d\u043e\u0433\u043e) \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f; \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f (\u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c), \u0430 \u044d\u0442\u043e\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439, \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u2014 \u043e\u043f\u044f\u0442\u044c \u00ab\u0432 \u0432\u043e\u0437\u0434\u0443\u0445\u0435\u00bb. \u0412 \u043e\u0431\u0449\u0435\u043c, \u043d\u0435 \u043a\u0440\u0443\u0442\u043e.<br \/>  \u041e\u0431\u0440\u0430\u0442\u0438\u043c\u0441\u044f \u043a <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/memory\">\u0443\u043c\u043d\u044b\u043c \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f\u043c<\/a>. \u041d\u0443\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043a\u0430\u043a\u043e\u0432\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0430 \u0432\u043b\u0430\u0434\u0435\u043d\u0438\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u0434\u0432\u0443\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430: \u0435\u0434\u0438\u043d\u043e\u043b\u0438\u0447\u043d\u043e\u0435 \u0432\u043b\u0430\u0434\u0435\u043d\u0438\u0435 (<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/memory\/unique_ptr\">std::unique_ptr<\/a>) \u0438\u043b\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u043c\u043e\u0435 (<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/memory\/shared_ptr\">std::shared_ptr<\/a>). <i>Holder<\/i>, \u043a\u0440\u043e\u043c\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0430\u043c\u0438\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u0435\u043c \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0434\u043e\u043b\u0436\u0435\u043d \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0432 <i>EventHandler&#8217;\u0435<\/i>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u043c\u043e\u0435 \u0432\u043b\u0430\u0434\u0435\u043d\u0438\u0435, \u0430 \u0434\u043b\u044f <i>EventHandler&#8217;\u0430<\/i> \u2014 \u0435\u0434\u0438\u043d\u043e\u043b\u0438\u0447\u043d\u043e\u0435, \u0442.\u043a. \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<br \/>  \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u044d\u0442\u0443 \u0438\u0434\u0435\u044e:  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class AbstractEventHandler {     . . .     public:         virtual ~AbstractEventHandler() {}     . . . };  template&lt;class ...Types&gt; using THandlerPtr = std::unique_ptr&lt;AbstractEventHandler&lt;Types...&gt;&gt;; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">namespace {     template&lt;class TSome&gt;     struct HandlerCast     {         template&lt;class ...Types&gt;         static constexpr THandlerPtr&lt;Types...&gt; cast( TSome& some )         {             return static_cast&lt;THandlerPtr&lt;Types...&gt;&gt;( some );         }     };     template&lt;class TPtr&gt;     struct HandlerCast&lt;std::shared_ptr&lt;TPtr&gt;&gt;     {         template&lt;class ...Types&gt;         static constexpr THandlerPtr&lt;Types...&gt; cast( std::shared_ptr&lt;TPtr&gt; some )         {             return HandlerCast&lt;TPtr&gt;::cast&lt;Types...&gt;( *some );         }     }; } \/\/ template&lt;class ...TParams&gt; class IEvent {     public:         template&lt;class TSome&gt;         bool operator+=( TSome&& some )         {            return addHandler( HandlerCast&lt;TSome&gt;::cast&lt;TParams...&gt;( some ) );         }         template&lt;class TSome&gt;         bool operator-=( TSome&& some )         {             return removeHandler( HandlerCast&lt;TSome&gt;::cast&lt;TParams...&gt;( some ) );         }     protected:         using TEventHandlerPtr = THandlerPtr&lt;TParams...&gt;;         IEvent() {}         virtual bool addHandler( TEventHandlerPtr eventHandler ) = 0;         virtual bool removeHandler( TEventHandlerPtr eventHandler ) = 0; }; template&lt;class ...TParams&gt; class TEvent : public IEvent&lt;TParams...&gt; {     using TEventHandlerIt = typename std::list&lt;TEventHandlerPtr&gt;::const_iterator;     public:          TEvent()         {             . . .         }         ~TEvent()         {             \/\/ empty         }     protected:         virtual bool addHandler( TEventHandlerPtr eventHandler ) override         {             std::unique_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );             if( findEventHandler( eventHandler ) == m_handlers.end() )             {                 m_handlers.push_back( std::move( eventHandler ) );                 return true;             }             return false;         }         virtual bool removeHandler( TEventHandlerPtr eventHandler ) override         {             . . .         }     private:         \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f 'm_handlerListMutex'         inline TEventHandlerIt findEventHandler( const TEventHandlerPtr& eventHandler ) const         {             return std::find_if( m_handlers.cbegin(), m_handlers.cend(), [ &eventHandler ]( const TEventHandlerPtr& oneHandler )             {                 return ( *oneHandler == *eventHandler );             } );         }         \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 'm_handlerListMutex'         inline void deleteHandler( TEventHandlerIt it )         {             m_handlers.erase( it );         }         std::list&lt;TEventHandlerPtr&gt; m_handlers;     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class TMethodHolder, class ...TParams&gt; class MethodEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     . . .     using TMethodHolderPtr = std::shared_ptr&lt;TMethodHolder&gt;;     public:         MethodEventHandler( TMethodHolderPtr methodHolder ) :             AbstractEventHandler&lt;TParams...&gt;(),             m_methodHolder( methodHolder )         {             assert( m_methodHolder != nullptr );         }     private:         TMethodHolderPtr m_methodHolder;     . . . }; template&lt;class TObject, class ...TParams&gt; class MethodHolder {     using MyType = MethodHolder&lt;TObject, TParams...&gt;;     using TMethod = void( TObject::* )( TParams... );     public:         MethodHolder( TObject& object, TMethod method )         {             . . .         }         template&lt;class ...TCallParams&gt;         operator THandlerPtr&lt;TCallParams...&gt;()         {             return THandlerPtr&lt;TCallParams...&gt;( new MethodEventHandler&lt;MyType, TCallParams...&gt;( \/* \u0427\u0422\u041e \u0421\u042e\u0414\u0410 \u041f\u0415\u0420\u0415\u0414\u0410\u0422\u042c? *\/ ) );         }     . . . }; template&lt;class TObject, class ...TParams&gt; std::shared_ptr&lt;MethodHolder&lt;TObject, TParams...&gt;&gt; createMethodEventHandler( TObject& object, void( TObject::*method )( TParams... ) ) {     return std::shared_ptr&lt;MethodHolder&lt;TObject, TParams...&gt;&gt;( new MethodHolder&lt;TObject, TParams...&gt;( object, method ) ); } #define METHOD_HANDLER( Object, Method ) createMethodEventHandler( Object, &Method ) #define MY_METHOD_HANDLER( Method ) METHOD_HANDLER( *this, Method ) <\/code><\/pre>\n<p>  \u041e\u0431\u043e \u0432\u0441\u0451\u043c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443.<br \/>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0438 \u0435\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438. \u0412 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0438\u043f\u044b \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <i>static_cast<\/i> \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u043b\u0435\u0436\u0438\u0442 \u00ab\u0432\u043d\u0443\u0442\u0440\u0438\u00bb <i>std::shared_ptr<\/i>. \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043b\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 <i>HandlerCast<\/i>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u0432\u043e\u0435\u0439 \u0447\u0430\u0441\u0442\u043d\u043e\u0439 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043e\u0431\u044a\u0435\u043a\u0442\u0443 \u0432\u043d\u0443\u0442\u0440\u0438 <i>std::shared_ptr<\/i>, \u0430 \u0443\u0436\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044f \u0441 \u043d\u0438\u043c (\u0432 \u0441\u0432\u043e\u0435\u0439 \u043d\u0435\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438), \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442 \u0441\u0442\u0430\u0440\u044b\u0439 \u0434\u043e\u0431\u0440\u044b\u0439 <i>static_cast<\/i>.<br \/>  \u0421\u0430\u043c\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435; \u0437\u0434\u0435\u0441\u044c \u0442\u043e\u0436\u0435 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0436\u043d\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u0435\u043c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0443\u0434\u0430\u043b\u044f\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u0438 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438; \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u043c\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u0441 \u044d\u0442\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432\u0430\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/move\">std::move<\/a>, \u0442.\u043a. <i>std::unique_ptr<\/i> \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 (\u0447\u0442\u043e \u0432\u0435\u0441\u044c\u043c\u0430 \u043b\u043e\u0433\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0439 \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0438).<br \/>  \u041f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c. \u041f\u043e \u0441\u0442\u0430\u0440\u043e\u0439 \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0438\u0437 \u043d\u0438\u0445, \u0432\u0442\u043e\u0440\u043e\u0439 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d. \u0418 \u0437\u0434\u0435\u0441\u044c, \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0432\u0441\u0451 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044e \u0442\u0438\u043f\u043e\u0432 \u0445\u0440\u0430\u043d\u0438\u043c\u044b\u0445\/\u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441\u043e \u0441\u0441\u044b\u043b\u043e\u043a\/\u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439 \u043d\u0430 \u0443\u043c\u043d\u044b\u0435 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0438.<br \/>  \u041d\u043e \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u0442\u043e\u043d\u043a\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u0424\u0443\u043d\u043a\u0446\u0438\u044f <i>createMethodEventHandler<\/i> \u0432\u0435\u0440\u043d\u0451\u0442 <i>std::shared_ptr<\/i> \u043d\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <i>MethodHolder<\/i>. \u0427\u0443\u0442\u044c \u043f\u043e\u0437\u0436\u0435 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u043f\u043e\u043f\u044b\u0442\u043a\u0430 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0435\u0433\u043e \u043a \u0442\u0438\u043f\u0443 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 (<i>MethodEventHandler<\/i>), \u0433\u0434\u0435 \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <i>MethodEventHandler<\/i>, \u043f\u0435\u0440\u0435\u0434\u0430\u0432 \u0435\u043c\u0443 \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>std::shared_ptr<\/i> \u043d\u0430 \u0441\u0435\u0431\u044f. \u0418\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u043e\u043d\u043e \u0438 \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <i>MethodHolder&#8217;\u0430<\/i> \u043f\u043e\u0437\u0436\u0435 \u0443\u0434\u0430\u043b\u0438\u043b\u0441\u044f \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <i>MethodEventHandler&#8217;\u0430<\/i>. \u041d\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0443 <i>MethodHolder&#8217;\u0430<\/i> \u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a \u0443\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u043c\u0443 <i>std::shared_ptr<\/i>, \u0445\u0440\u0430\u043d\u044f\u0449\u0435\u043c\u0443 \u0435\u0433\u043e \u0441\u0430\u043c\u043e\u0433\u043e.<br \/>  \u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 <i>MethodHolder&#8217;\u0435<\/i> \u0443\u043c\u043d\u044b\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0441\u0435\u0431\u044f \u0436\u0435. \u041e\u0434\u043d\u0430\u043a\u043e \u0447\u0442\u043e\u0431\u044b \u0442\u043e\u0442 \u043d\u0435 \u0432\u043b\u0438\u044f\u043b \u043d\u0430 \u0435\u0433\u043e \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/memory\/weak_ptr\">std::weak_ptr<\/a>:  <\/p>\n<pre><code class=\"cpp\">template&lt;class TObject, class ...TParams&gt; class MethodHolder {     using MyType = MethodHolder&lt;TObject, TParams...&gt;;     using TMethod = void( TObject::* )( TParams... );     public:         template&lt;class ...TCallParams&gt;         operator THandlerPtr&lt;TCallParams...&gt;()         {             return THandlerPtr&lt;TCallParams...&gt;( new MethodEventHandler&lt;MyType, TCallParams...&gt;( m_me.lock() ) );         }         template&lt;class TObject, class ...TParams&gt;         static std::shared_ptr&lt;MyType&gt; create( TObject& object, TMethod method )         {             std::shared_ptr&lt;MyType&gt; result( new MyType( object, method ) );             result-&gt;m_me = result;             return result;         }     private:         MethodHolder( TObject& object, TMethod method ) :             m_object( object ),             m_method( method )         {             assert( m_method != nullptr );         }         TObject& m_object;         TMethod m_method;         std::weak_ptr&lt;MyType&gt; m_me; }; template&lt;class TObject, class ...TParams&gt; std::shared_ptr&lt;MethodHolder&lt;TObject, TParams...&gt;&gt; createMethodEventHandler( TObject& object, void( TObject::*method )( TParams... ) ) {     return MethodHolder&lt;TObject, TParams...&gt;::create( object, method ); } <\/code><\/pre>\n<p>  \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u043f\u043e\u043d\u044f\u0442\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u0438\u0432\u0435\u0434\u0443 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u044b\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0438\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u043c\u043e\u0438 \u0438\u0437\u0432\u0438\u043d\u0435\u043d\u0438\u044f \u0437\u0430 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u043a\u0430\u043b\u0430\u043c\u0431\u0443\u0440):<\/p>\n<ul>\n<li>\u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 (<i>m_handlers.erase( it );<\/i>), \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0432\u044b\u0437\u043e\u0432\u0443 \u0435\u0433\u043e \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430;<\/li>\n<li>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>std::unique_ptr<\/i>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0432\u044b\u0437\u043e\u0432\u0443 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430;<\/li>\n<li>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>MethodEventHandler<\/i>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u043f\u043e\u043b\u0435 <i>m_methodHolder<\/i>, \u044f\u0432\u043b\u044f\u044e\u0449\u0435\u0435\u0441\u044f <i>std::shared_ptr<\/i>;<\/li>\n<li>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>std::shared_ptr<\/i>; \u043e\u043d \u0432\u0438\u0434\u0438\u0442, \u0447\u0442\u043e \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u0432 \u0434\u043e\u0441\u0442\u0438\u0433 \u043d\u0443\u043b\u044f (\u0442.\u043a. \u043d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0438\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043e\u043d \u0431\u044b\u043b \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u043c) \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 (<i>MethodHolder<\/i>); \u043e\u0434\u043d\u0430\u043a\u043e \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u043b\u043e\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u0441\u0441\u044b\u043b\u043e\u043a <i>std::weak_ptr<\/i> \u043f\u043e\u043a\u0430 \u043d\u0435 \u0440\u0430\u0432\u0435\u043d \u043d\u0443\u043b\u044e;<\/li>\n<li>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>MethodHolder<\/i>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u044e \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u0435\u0439, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435, \u043f\u043e\u043b\u044f <i>m_me<\/i>, \u044f\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e\u0441\u044f <i>std::weak_ptr<\/i>;<\/li>\n<li>\u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>std::weak_ptr<\/i>; \u0435\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0443\u0436\u0435 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d; \u0442.\u043a. \u0441\u0447\u0451\u0442\u0447\u0438\u043a \u0441\u0441\u044b\u043b\u043e\u043a <i>std::weak_ptr<\/i> \u0441\u0442\u0430\u043b \u0440\u0430\u0432\u043d\u044b\u043c \u043d\u0443\u043b\u044e, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u043b\u043e\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f;<\/li>\n<li>\u043f\u0440\u043e\u0444\u0438\u0442.<\/li>\n<\/ul>\n<p>  \u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 <i>AbstractEventHandler<\/i> \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c; \u0438\u043d\u0430\u0447\u0435 \u043f\u043e\u0441\u043b\u0435 \u043f\u0443\u043d\u043a\u0442\u0430 <b>2<\/b> \u0432 \u043f\u0443\u043d\u043a\u0442\u0435 <b>3<\/b> \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0451\u0442 \u0432\u044b\u0437\u043e\u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 <i>AbstractEventHandler<\/i> \u0438 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u043d\u0435 \u0431\u0443\u0434\u0443\u0442.<\/p>\n<p>  <a name=\"Joins\"><\/a><\/p>\n<h1>\u0421\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430<\/h1>\n<p>  \u0412 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432, \u043a\u043e\u0433\u0434\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\/\u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0438\u0437 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0435\u0441\u044c\u043c\u0430 \u0447\u0430\u0441\u0442\u043e (\u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u043b\u043e\u0433\u0438\u043a\u0435), \u043d\u0435 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u0438\u0442\u044c\u0441\u044f, \u0434\u043e\u0441\u0442\u0430\u0432\u0430\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0438 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u0447\u0442\u043e\u0431\u044b \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u0439 \u0440\u0430\u0437 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443\/\u043e\u0442\u043f\u0438\u0441\u043a\u0443 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0410 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u044d\u0442\u0438\u043c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435\u043c, \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044f\/\u0443\u0434\u0430\u043b\u044f\u044f \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438\u0437 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f. \u0420\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...Types&gt; using THandlerPtr = std::shared_ptr&lt;AbstractEventHandler&lt;Types...&gt;&gt;; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class IEvent {     . . .     protected:         using TEventHandlerPtr = THandlerPtr&lt;TParams...&gt;;         virtual bool isHandlerAdded( const TEventHandlerPtr& eventHandler ) const = 0;         virtual bool addHandler( TEventHandlerPtr eventHandler ) = 0;         virtual bool removeHandler( TEventHandlerPtr eventHandler ) = 0;     friend class HandlerEventJoin&lt;TParams...&gt;;     . . . }; template&lt;class ...TParams&gt; class TEvent : public IEvent&lt;TParams...&gt; {     . . .     protected:         virtual bool isHandlerAdded( const TEventHandlerPtr& eventHandler ) const override         {             std::shared_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );             return ( findEventHandler( eventHandler ) != m_handlers.end() );         }         virtual bool addHandler( TEventHandlerPtr eventHandler ) override { . . . }         virtual bool removeHandler( TEventHandlerPtr eventHandler ) override { . . . }     private:         \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f 'm_handlerListMutex'         inline TEventHandlerIt findEventHandler( const TEventHandlerPtr& eventHandler ) const { . . . }                  std::list&lt;TEventHandlerPtr&gt; m_handlers;         mutable std::shared_mutex m_handlerListMutex;     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class HandlerEventJoin {     public:         HandlerEventJoin( IEvent&lt;TParams...&gt;& _event, THandlerPtr&lt;TParams...&gt; handler ) :             m_event( _event ),             m_handler( handler )         {         }         inline bool isJoined() const         {             return m_event.isHandlerAdded( m_handler );         }         inline bool join()         {             return m_event.addHandler( m_handler );                 }         inline bool unjoin()         {             return m_event.removeHandler( m_handler );                 }     private:         IEvent&lt;TParams...&gt;& m_event;         THandlerPtr&lt;TParams...&gt; m_handler; }; <\/code><\/pre>\n<p>  \u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u0442\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e <i>std::shared_ptr<\/i> \u0432\u043c\u0435\u0441\u0442\u043e <i>std::unique_ptr<\/i>.<br \/>  \u041e\u0434\u043d\u0430\u043a\u043e \u0434\u0430\u043d\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u043a\u0430\u043a \u043f\u043e \u043c\u043d\u0435, \u0441\u043b\u0435\u0433\u043a\u0430 \u043d\u0435\u0443\u0434\u043e\u0431\u0435\u043d \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438. \u042d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0431\u0435\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0438\u043d\u0441\u0442\u0430\u043d\u0446\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u0448\u0430\u0431\u043b\u043e\u043d \u043a\u043b\u0430\u0441\u0441\u0430. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u044d\u0442\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430-\u043f\u0440\u0435\u0434\u043a\u0430 \u0438 \u043e\u0431\u0451\u0440\u0442\u043a\u0438:  <\/p>\n<pre><code class=\"cpp\">class AbstractEventJoin {     public:         virtual ~AbstractEventJoin() {}          virtual bool isJoined() const = 0;         virtual bool join() = 0;         virtual bool unjoin() = 0;     protected:         AbstractEventJoin() {} }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class HandlerEventJoin : public AbstractEventJoin {     . . .     public:         virtual inline bool isJoined() const override { . . . }         virtual inline bool join() override { . . . }         virtual inline bool unjoin() override { . . . }     . . . }; <\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">class EventJoinWrapper {     public:         template&lt;class TSome, class ...TParams&gt;         inline EventJoinWrapper( IEvent&lt;TParams...&gt;& _event, TSome&& handler ) :             m_eventJoin( std::make_shared&lt;HandlerEventJoin&lt;TParams...&gt;&gt;( _event, HandlerCast&lt;TSome&gt;::cast&lt;TParams...&gt;( handler ) ) )         {         }         constexpr EventJoinWrapper() :             m_eventJoin( nullptr )         {         }         ~EventJoinWrapper()         {             if( m_eventJoin != nullptr )                 delete m_eventJoin;         }         operator bool() const         {             return isJoined();         }         bool isAssigned() const         {             return ( m_eventJoin != nullptr );         }         bool isJoined() const         {             return ( m_eventJoin != nullptr && m_eventJoin-&gt;isJoined() );         }         bool join()         {             return ( m_eventJoin != nullptr ? m_eventJoin-&gt;join() : false );         }         bool unjoin()         {             return ( m_eventJoin != nullptr ? m_eventJoin-&gt;unjoin() : false );         }     private:         AbstractEventJoin* m_eventJoin; }; using EventJoin = EventJoinWrapper; <\/code><\/pre>\n<p>  <i>HandlerCast<\/i> \u2014 \u044d\u0442\u043e \u0442\u0430 \u0436\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0430\u0441\u044c <a href=\"#GarbageCollection\">\u0437\u0434\u0435\u0441\u044c<\/a>. \u041a\u0441\u0442\u0430\u0442\u0438, \u0432\u0430\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>AbstractEventJoin<\/i> \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0438 \u0435\u0433\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 <i>EventJoinWrapper<\/i> \u0432\u044b\u0437\u0432\u0430\u043b\u0441\u044f \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 <i>HandlerEventJoin<\/i>, \u0438\u043d\u0430\u0447\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u043c \u043d\u0435 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u0435 <i>THandlerPtr<\/i> \u0438, \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0441\u0430\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a.<br \/>  \u0414\u0430\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u043e\u0439, \u043e\u0434\u043d\u0430\u043a\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434. \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <i>EventJoinWrapper<\/i> \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c\u0443 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044e <i>m_eventJoin<\/i> \u0432 \u0435\u0433\u043e \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <i>std::shared_ptr<\/i> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 <i>AbstractEventJoin<\/i>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u043b\u0435\u0433\u043a\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u0441\u0435\u043c\u0430\u043d\u0442\u0438\u043a\u0443 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f (\u0438 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f), \u0442.\u043a. \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0447\u0430\u0441\u0442\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0435\u0439.  <\/p>\n<pre><code class=\"cpp\">class EventJoinWrapper {     public:         EventJoinWrapper( EventJoinWrapper&& other ) :             m_eventJoin( std::move( other.m_eventJoin ) )         {         }         EventJoinWrapper( EventJoinWrapper& other ) :             m_eventJoin( other.m_eventJoin )         {         }         ~EventJoinWrapper() { \/*empty*\/ }                 EventJoinWrapper& operator=( EventJoinWrapper&& other )         {             m_eventJoin = std::move( other.m_eventJoin );             return *this;         }         EventJoinWrapper& operator=( const EventJoinWrapper& other )         {             m_eventJoin = other.m_eventJoin;             return *this;         }         . . .     private:         std::shared_ptr&lt;AbstractEventJoin&gt; m_eventJoin; }; <\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f:  <\/p>\n<pre><code class=\"cpp\">template&lt;class ...TParams&gt; class IEvent {     . . .     public:         template&lt;class TSome&gt;         EventJoin operator+=( TSome&& some )         {             EventJoin result( *this, std::forward&lt;TSome&gt;( some ) );             result.join();             return result;         }     . . . }; <\/code><\/pre>\n<p>  \u0410 \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0437\u0440\u0443\u043b\u0438\u0432\u0430\u043d\u0438\u044f \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u043e\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u043e <i>include&#8217;\u0430\u043c<\/i> <i>(IEvent &lt;= EventJointWrapper.hpp; EventJointWrapper &lt;= HandlerEventJoin.hpp; HandlerEventJoin &lt;= IEvent.hpp)<\/i> \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435\u043c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u043d\u0430 <i>.h<\/i> \u0438 <i>.hpp<\/i> \u0441 \u044d\u0442\u0438\u043c \u0434\u0430\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<br \/>  \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u043e\u0432 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u0442\u0435\u043c \u0436\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c, \u0447\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043f\u0440\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435:  <\/p>\n<pre><code class=\"cpp\">struct EventHolder {     TEvent&lt;const std::string&&gt; onEvent; }; struct MethodsHolder {     void method1( const std::string& ) {}     void method2( std::string ) {}     void method3( std::string&& ) {}     void method4( std::string& ) {}     void method5( const int& ) {} }; int main( int argc, char* argv[] ) {     EventHolder _eventHolder;     MethodsHolder _methodsHolder;      EventJoin join1 = EventJoin( _eventHolder.onEvent, METHOD_HANDLER( _methodsHolder, MethodsHolder::method1 ) );  \/\/ ok     EventJoin join2 = EventJoin( _eventHolder.onEvent, METHOD_HANDLER( _methodsHolder, MethodsHolder::method2 ) );  \/\/ ok     EventJoin join3 = EventJoin( _eventHolder.onEvent, METHOD_HANDLER( _methodsHolder, MethodsHolder::method3 ) );  \/\/ error     EventJoin join4 = EventJoin( _eventHolder.onEvent, METHOD_HANDLER( _methodsHolder, MethodsHolder::method4 ) );  \/\/ error     EventJoin join5 = EventJoin( _eventHolder.onEvent, METHOD_HANDLER( _methodsHolder, MethodsHolder::method5 ) );  \/\/ error          return 0; } <\/code><\/pre>\n<p>  \u041f\u043b\u044e\u0441, \u043c\u043e\u0436\u043d\u043e \u00ab\u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u00bb\/\u00ab\u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u00bb \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044f (\u0434\u043b\u044f \u0447\u0435\u0433\u043e, \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438\u0441\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f):  <\/p>\n<pre><code class=\"cpp\">struct EventHolder {     TEvent&lt;const std::string&, unsigned int&gt; onEvent; }; struct MethodsHolder {     void handleEvent( const std::string& text, unsigned int count )     {         std::cout &lt;&lt; &quot;Text '&quot; &lt;&lt; text &lt;&lt; &quot;' handled &quot; &lt;&lt; count &lt;&lt; &quot; times.&quot; &lt;&lt; std::endl;     } }; int main__( int argc, char* argv[] ) {     EventHolder _eventHolder;     MethodsHolder methodsHolder;     EventJoin eventJoin = EventJoin( _eventHolder.onEvent, METHOD_HANDLER( methodsHolder, MethodsHolder::handleEvent ) );      static const std::string handlingText = &quot;testing...&quot;;     for( int i = 0; i &lt; 10; ++i )     {         if( eventJoin.isJoined() )             eventJoin.unjoin();         else             eventJoin.join();         _eventHolder.onEvent( handlingText, i );     }      return 0; } <\/code><\/pre>\n<p>  <\/p>\n<pre><code>Text 'testing...' handled 0 times. Text 'testing...' handled 2 times. Text 'testing...' handled 4 times. Text 'testing...' handled 6 times. Text 'testing...' handled 8 times. <\/code><\/pre>\n<p>  <a name=\"Totals\"><\/a><\/p>\n<h1>\u0418\u0442\u043e\u0433<\/h1>\n<p>  \u0421\u043f\u0435\u0440\u0432\u0430 \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u044c\u044e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043a\u043e\u0440\u043e\u0442\u043a\u043e \u0438 \u0441\u0436\u0430\u0442\u043e \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u043e\u0432\u0430\u043b\u0435\u043d\u0430.<br \/>  \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u043e\u0441\u043f\u043e\u0441\u043e\u0431\u043d\u0430 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0445\u043e\u0442\u044c \u043a\u043e\u043c\u0443-\u0442\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u0430.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0412\u0435\u0441\u044c\u043c\u0430 \u0433\u0440\u043e\u043c\u043e\u0437\u0434\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#include &lt;iostream&gt; #include &lt;functional&gt; #include &quot;events\/event.hpp&quot; #include &quot;events\/handler\/methodeventhandler.hpp&quot; #include &quot;events\/handler\/functoreventhandler.hpp&quot; #include &quot;events\/join\/handlereventjoin.hpp&quot; #include &quot;events\/join\/eventjoinwrapper.hpp&quot;  class Foo {     public:         Foo() :             onMake( m_onMake ),             m_onMake(),             m_onMakeInner(),             m_makeCount( 0 )         {             m_onMakeInner += FUNCTOR_HANDLER( m_onMake );         }         IEvent&lt;unsigned int&gt;& onMake;         void make()         {             m_onMakeInner( m_makeCount++ );         }     private:         TEvent&lt;unsigned int&gt; m_onMake, m_onMakeInner;         unsigned int m_makeCount; }; namespace instances {     Foo& getFoo()     {         static Foo _foo;         return _foo;     } } \/\/ instances  struct FunctorHandler {     void operator()( unsigned int makeCount ); }; void functionHandler( unsigned int makeCount ); class ClassHandler {     public:         void handle( unsigned int makeCount ); }; namespace instances {     FunctorHandler& getFunctorHandler()     {         static FunctorHandler _functorHandler;         return _functorHandler;     }     std::function&lt;void( unsigned int )&gt;& getStdFunctionHandler()     {         static std::function&lt;void( unsigned int )&gt; _stdFunctionHandler = []( unsigned int makeCount )         {             std::cout &lt;&lt; &quot;It's std::function handler&quot; &lt;&lt; std::endl;             if( makeCount &gt;= 2 )                 instances::getFoo().onMake -= STD_FUNCTION_HANDLER( instances::getStdFunctionHandler() );         };         return _stdFunctionHandler;     }     ClassHandler& getClassHandler()     {         static ClassHandler _classHandler;         return _classHandler;     } } \/\/ instances void FunctorHandler::operator()( unsigned int makeCount ) {     std::cout &lt;&lt; &quot;It's functor handler&quot; &lt;&lt; std::endl;     if( makeCount &gt;= 0 )         instances::getFoo().onMake -= FUNCTOR_HANDLER( instances::getFunctorHandler() ); } void functionHandler( unsigned int makeCount ) {     std::cout &lt;&lt; &quot;It's function handler&quot; &lt;&lt; std::endl;     if( makeCount &gt;= 3 )         instances::getFoo().onMake -= FUNCTION_HANDLER( functionHandler ); } void ClassHandler::handle( unsigned int makeCount ) {     std::cout &lt;&lt; &quot;It's method handler&quot; &lt;&lt; std::endl;     if( makeCount &gt;= 4 )         instances::getFoo().onMake -= MY_METHOD_HANDLER( ClassHandler::handle ); }  int main( int argc, char* argv[] ) {     Foo& foo = instances::getFoo();      auto lambdaHandler = []( unsigned int )     {         std::cout &lt;&lt; &quot;It's lambda handler&quot; &lt;&lt; std::endl;     };      foo.onMake += FUNCTOR_HANDLER( instances::getFunctorHandler() );     foo.onMake += LAMBDA_HANDLER( lambdaHandler );     EventJoin lambdaJoin = foo.onMake += LAMBDA_HANDLER( ( [ &foo, &lambdaHandler ]( unsigned int makeCount )     {         if( makeCount &gt;= 1 )             foo.onMake -= LAMBDA_HANDLER( lambdaHandler );     } ) );     foo.onMake += STD_FUNCTION_HANDLER( instances::getStdFunctionHandler() );     foo.onMake += FUNCTION_HANDLER( functionHandler );     foo.onMake += METHOD_HANDLER( instances::getClassHandler(), ClassHandler::handle );      for( int i = 0; i &lt; 6; ++i )     {         std::cout &lt;&lt; &quot;Make &quot; &lt;&lt; i &lt;&lt; &quot; time:&quot; &lt;&lt; std::endl;         foo.make();         std::cout &lt;&lt; std::endl;     }          lambdaJoin.unjoin();         return 0; } <\/code><\/pre>\n<p>  \u0412\u044b\u0432\u043e\u0434:  <\/p>\n<pre><code>Make 0 time: It's functor handler It's lambda handler It's std::function handler It's function handler It's method handler  Make 1 time: It's lambda handler It's std::function handler It's function handler It's method handler  Make 2 time: It's std::function handler It's function handler It's method handler  Make 3 time: It's function handler It's method handler  Make 4 time: It's method handler  Make 5 time:  <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  \u0421\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0440\u044f\u0434 \u0432\u0430\u0436\u043d\u044b\u0445 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432:<\/p>\n<ul>\n<li>\u043d\u0435 \u043e\u0433\u043e\u0432\u0430\u0440\u0438\u0432\u0430\u043b\u043e\u0441\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0443\u043f\u043e\u043c\u044f\u043d\u0443, \u0447\u0442\u043e \u0441\u0430\u043c\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u043c, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442, \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f;<\/li>\n<li>\u0441\u0435\u0439\u0447\u0430\u0441 \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b (\u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0447\u043b\u0435\u043d\u044b \u043a\u043b\u0430\u0441\u0441\u0430); \u0434\u0443\u043c\u0430\u044e, \u0435\u0441\u043b\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0442\u0430\u043a\u0430\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c, \u043d\u0435\u0442\u0440\u0443\u0434\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u043e\u0432\u044b\u0439 \u0442\u0438\u043f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0443\u0436\u0435 \u0438\u043c\u0435\u044e\u0449\u0438\u0445\u0441\u044f.<\/li>\n<\/ul>\n<p>  \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0432 \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b, \u043e\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0435 \u0432 \u0441\u0442\u0430\u0442\u044c\u0435 \u0434\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0441\u0442\u0438 \u0438 \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430:<\/p>\n<ul>\n<li>\u0442\u0438\u043f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0442\u043e\u0434\u0430 (\u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0447\u043b\u0435\u043d\u0430 \u043a\u043b\u0430\u0441\u0441\u0430) \u0434\u043b\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u044b\u043c, \u043d\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e <i>void<\/i> (\u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432-\u0444\u0443\u043d\u043a\u0442\u043e\u0440\u043e\u0432 \u044d\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u043e\u0441\u044c \u0438 \u0442\u0430\u043a);<\/li>\n<li>\u0432\u0441\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u0430\u0432\u0451\u0440\u043d\u0443\u0442\u0430 \u0432 <i>namespace&#8217;\u044b<\/i> \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 (\u0435\u0441\u043b\u0438 \u043a\u043e\u043c\u0443-\u0442\u043e \u044d\u0442\u043e \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043b\u0438\u0448\u043d\u0438\u043c, \u0438\u0445 \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0443\u0431\u0440\u0430\u0442\u044c);<\/li>\n<li>\u043a\u043e\u0435-\u0433\u0434\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/noexcept_spec\">noexcept<\/a>.<\/li>\n<\/ul>\n<p>  \u0412\u0441\u0435\u043c \u0442\u0435\u043c, \u043a\u0442\u043e \u0434\u043e\u0447\u0438\u0442\u0430\u043b \u0434\u043e\u0441\u044e\u0434\u0430 \u0445\u043e\u0442\u044f \u0431\u044b \u043f\u043e \u0434\u0438\u0430\u0433\u043e\u043d\u0430\u043b\u0438, \u043d\u0438\u0437\u043a\u0438\u0439 \u043f\u043e\u043a\u043b\u043e\u043d. \u041f\u0440\u0438\u043b\u0430\u0433\u0430\u044e \u0432\u0435\u0441\u044c \u043a\u043e\u0434; \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u0435\u0449\u0451 \u0438 <a href=\"https:\/\/github.com\/ZolotovPavel\/EventHandling\">\u0437\u0434\u0435\u0441\u044c<\/a>.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u0412\u0435\u0441\u044c \u043a\u043e\u0434<\/b><\/p>\n<div class=\"spoiler_text\">\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/helpers\/is_equatable.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;type_traits&gt;   template&lt;class T&gt; class is_equatable {     private:          template&lt;class U&gt;         static constexpr std::true_type exists( decltype( std::declval&lt;U&gt;() == std::declval&lt;U&gt;() )* = nullptr ) noexcept;          template&lt;class U&gt;         static constexpr std::false_type exists( ... ) noexcept;      public:          static constexpr bool value = decltype( exists&lt;T&gt;( nullptr ) )::value; }; <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/handlers\/abstracteventhandler.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &quot;eventhandlerptr.h&quot;   namespace events {  namespace handlers {   template&lt;class ...TParams&gt; class AbstractEventHandler {     using MyType = AbstractEventHandler&lt;TParams...&gt;;      public:          virtual ~AbstractEventHandler() {}          virtual void call( TParams... params ) = 0;          bool operator==( const MyType& other ) const noexcept         {             return isEquals( other );         }         bool operator!=( const MyType& other ) const noexcept         {             return !( *this == other );         }      protected:              AbstractEventHandler() {}          virtual bool isEquals( const MyType& other ) const noexcept = 0; };   } \/\/ handlers  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/handlers\/eventhandlerptr.h<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;memory&gt;   namespace events {  namespace handlers {   template&lt;class ...TParams&gt; class AbstractEventHandler;   template&lt;class ...Types&gt; using TEventHandlerPtr = std::shared_ptr&lt;AbstractEventHandler&lt;Types...&gt;&gt;;   } \/\/ handlers  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/handlers\/functoreventhandler.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;memory&gt; #include &lt;assert.h&gt; #include &quot;abstracteventhandler.hpp&quot; #include &quot;..\/helpers\/is_equatable.hpp&quot;   namespace events {  namespace handlers {   namespace {      template&lt;class TFunctor, class ...TParams&gt;     struct IsFunctorParamsCompatible     {         private:              template&lt;class TCheckedFunctor, class ...TCheckedParams&gt;             static constexpr std::true_type exists( decltype( std::declval&lt;TCheckedFunctor&gt;()( std::declval&lt;TCheckedParams&gt;()... ) )* = nullptr ) noexcept;                          template&lt;class TCheckedFunctor, class ...TCheckedParams&gt;             static constexpr std::false_type exists( ... ) noexcept;          public:              static constexpr bool value = decltype( exists&lt;TFunctor, TParams...&gt;( nullptr ) )::value;     };  } \/\/   template&lt;class TFunctor&gt; class FunctorHolder;  template&lt;class TFunctor, class ...TParams&gt; class FunctorEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     using MyType = FunctorEventHandler&lt;TFunctor, TParams...&gt;;     using TFunctorHolderPtr = std::shared_ptr&lt;FunctorHolder&lt;TFunctor&gt;&gt;;      public:          FunctorEventHandler( TFunctorHolderPtr functorHolder ) :             AbstractEventHandler&lt;TParams...&gt;(),             m_functorHolder( functorHolder )         {             assert( m_functorHolder != nullptr );         }          virtual void call( TParams... params ) override         {             static_assert( IsFunctorParamsCompatible&lt;TFunctor, TParams...&gt;::value, &quot;Event and functor arguments are not compatible&quot; );              m_functorHolder-&gt;m_functor( params... );         }      protected:          virtual bool isEquals( const AbstractEventHandler&lt;TParams...&gt;& other ) const noexcept override          {             const MyType* _other = dynamic_cast&lt;const MyType*&gt;( &other );             return ( _other != nullptr && *m_functorHolder == *_other-&gt;m_functorHolder );         }      private:          TFunctorHolderPtr m_functorHolder; };   namespace {      template&lt;class TEqu, class TEnabled = void&gt;     struct EqualityChecker;      template&lt;class TEquatable&gt;     struct EqualityChecker&lt;TEquatable, typename std::enable_if&lt;is_equatable&lt;TEquatable&gt;::value&gt;::type&gt;     {         static constexpr bool isEquals( const TEquatable& operand1, const TEquatable& operand2 ) noexcept         {             return ( operand1 == operand2 );         }     };      template&lt;class TNonEquatable&gt;     struct EqualityChecker&lt;TNonEquatable, typename std::enable_if&lt;!is_equatable&lt;TNonEquatable&gt;::value&gt;::type&gt;     {         static constexpr bool isEquals( const TNonEquatable& operand1, const TNonEquatable& operand2 ) noexcept         {             return ( &operand1 == &operand2 );         }     };  } \/\/  template&lt;class TFunctor&gt; class FunctorHolder {     using MyType = FunctorHolder&lt;TFunctor&gt;;      public:          template&lt;class ...TCallParams&gt;         operator TEventHandlerPtr&lt;TCallParams...&gt;()         {             return TEventHandlerPtr&lt;TCallParams...&gt;( new FunctorEventHandler&lt;TFunctor, TCallParams...&gt;( m_me.lock() ) );         }          bool operator==( const MyType& other ) const noexcept         {             return EqualityChecker&lt;TFunctor&gt;::isEquals( m_functor, other.m_functor );         }         bool operator!=( const MyType& other ) const noexcept         {             return !( *this == other );         }          template&lt;class TFunctor&gt;         static std::shared_ptr&lt;MyType&gt; create( TFunctor&& functor )         {             std::shared_ptr&lt;MyType&gt; result( new MyType( functor ) );             result-&gt;m_me = result;             return result;         }      private:          FunctorHolder( TFunctor& functor ) :             m_functor( functor ),             m_me()         {         }          TFunctor& m_functor;          std::weak_ptr&lt;MyType&gt; m_me;      template&lt;class TFunctor, class ...TParams&gt; friend class FunctorEventHandler; };   template&lt;class TFunctor&gt; std::shared_ptr&lt;FunctorHolder&lt;TFunctor&gt;&gt; createFunctorEventHandler( TFunctor&& functor ) {     return FunctorHolder&lt;TFunctor&gt;::create( functor ); }   } \/\/ handlers  } \/\/ events   #define     FUNCTOR_HANDLER( Functor )              ::events::handlers::createFunctorEventHandler( Functor ) #define     LAMBDA_HANDLER( Lambda )                FUNCTOR_HANDLER( Lambda ) #define     STD_FUNCTION_HANDLER( StdFunction )     FUNCTOR_HANDLER( StdFunction ) #define     FUNCTION_HANDLER( Function )            FUNCTOR_HANDLER( &Function ) <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/handlers\/methodeventhandler.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;memory&gt; #include &lt;assert.h&gt; #include &quot;abstracteventhandler.hpp&quot;   namespace events {  namespace handlers {   namespace {      template&lt;class TMethodHolder, class ...TParams&gt;     struct IsMethodParamsCompatible     {         private:              template&lt;class TCheckedMethodHolder, class ...TCheckedParams&gt;             static constexpr std::true_type exists( decltype( ( std::declval&lt;TCheckedMethodHolder&gt;().m_object.*std::declval&lt;TCheckedMethodHolder&gt;().m_method )( std::declval&lt;TCheckedParams&gt;()... ) )* = nullptr ) noexcept;                          template&lt;class TCheckedMethodHolder, class ...TCheckedParams&gt;             static constexpr std::false_type exists( ... ) noexcept;          public:              static constexpr bool value = decltype( exists&lt;TMethodHolder, TParams...&gt;( nullptr ) )::value;     };  } \/\/   template&lt;class TMethodHolder, class ...TParams&gt; class MethodEventHandler : public AbstractEventHandler&lt;TParams...&gt; {     using MyType = MethodEventHandler&lt;TMethodHolder, TParams...&gt;;     using TMethodHolderPtr = std::shared_ptr&lt;TMethodHolder&gt;;      public:          MethodEventHandler( TMethodHolderPtr methodHolder ) :             AbstractEventHandler&lt;TParams...&gt;(),             m_methodHolder( methodHolder )         {             assert( m_methodHolder != nullptr );         }          virtual void call( TParams... params ) override         {             static_assert( IsMethodParamsCompatible&lt;TMethodHolder, TParams...&gt;::value, &quot;Event and method arguments are not compatible&quot; );              ( m_methodHolder-&gt;m_object.*m_methodHolder-&gt;m_method )( params... );         }      protected:          virtual bool isEquals( const AbstractEventHandler&lt;TParams...&gt;& other ) const noexcept override         {             const MyType* _other = dynamic_cast&lt;const MyType*&gt;( &other );             return ( _other != nullptr && *m_methodHolder == *_other-&gt;m_methodHolder );         }      private:          TMethodHolderPtr m_methodHolder; };   template&lt;class TObject, class TResult, class ...TParams&gt; class MethodHolder {     using MyType = MethodHolder&lt;TObject, TResult, TParams...&gt;;     using TMethod = TResult( TObject::* )( TParams... );      public:          template&lt;class ...TCallParams&gt;         operator TEventHandlerPtr&lt;TCallParams...&gt;()         {             return TEventHandlerPtr&lt;TCallParams...&gt;( new MethodEventHandler&lt;MyType, TCallParams...&gt;( m_me.lock() ) );         }          bool operator==( const MyType& other ) const noexcept         {             return ( &m_object == &other.m_object && m_method == other.m_method );         }         bool operator!=( const MyType& other ) const noexcept         {             return !( *this == other );         }          template&lt;class TObject, class ...TParams&gt;         static std::shared_ptr&lt;MyType&gt; create( TObject& object, TMethod method )         {             std::shared_ptr&lt;MyType&gt; result( new MyType( object, method ) );             result-&gt;m_me = result;             return result;         }      private:          MethodHolder( TObject& object, TMethod method ) :             m_object( object ),             m_method( method )         {             assert( m_method != nullptr );         }          TObject& m_object;         TMethod m_method;          std::weak_ptr&lt;MyType&gt; m_me;      template&lt;class TMethodHolder, class ...TParams&gt; friend class MethodEventHandler;     template&lt;class TMethodHolder, class ...TParams&gt; friend struct IsMethodParamsCompatible; };   template&lt;class TObject, class TResult, class ...TParams&gt; std::shared_ptr&lt;MethodHolder&lt;TObject, TResult, TParams...&gt;&gt; createMethodEventHandler( TObject& object, TResult( TObject::*method )( TParams... ) ) {     return MethodHolder&lt;TObject, TResult, TParams...&gt;::create( object, method ); }   } \/\/ handlers  } \/\/ events   #define     METHOD_HANDLER( Object, Method )     ::events::handlers::createMethodEventHandler( Object, &Method ) #define     MY_METHOD_HANDLER( Method )          METHOD_HANDLER( *this, Method ) <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/handlers\/handlercast.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;memory&gt; #include &quot;eventhandlerptr.h&quot;   namespace events {  namespace handlers {   template&lt;class TSome&gt; struct HandlerCast {     template&lt;class ...Types&gt;     static constexpr TEventHandlerPtr&lt;Types...&gt; cast( TSome& some )     {         return static_cast&lt;TEventHandlerPtr&lt;Types...&gt;&gt;( some );     } };  template&lt;class TPtr&gt; struct HandlerCast&lt;std::shared_ptr&lt;TPtr&gt;&gt; {     template&lt;class ...Types&gt;     static constexpr TEventHandlerPtr&lt;Types...&gt; cast( std::shared_ptr&lt;TPtr&gt; some )     {         return HandlerCast&lt;TPtr&gt;::cast&lt;Types...&gt;( *some );     } };   } \/\/ handlers  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/event.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;type_traits&gt; #include &lt;list&gt; #include &lt;memory&gt; #include &lt;shared_mutex&gt; #include &lt;algorithm&gt; #include &lt;assert.h&gt; #include &quot;handlers\/abstracteventhandler.hpp&quot; #include &quot;handlers\/eventhandlerptr.h&quot; #include &quot;handlers\/handlercast.hpp&quot; #include &quot;joins\/eventjoinwrapper.hpp&quot;   namespace events {   namespace joins {     template&lt;class ...TParams&gt; class HandlerEventJoin; }  template&lt;class ...TParams&gt; class IEvent {     public:          template&lt;class TSome&gt;         EventJoin operator+=( TSome&& some )         {             EventJoin result( *this, std::forward&lt;TSome&gt;( some ) );             result.join();             return result;         }          template&lt;class TSome&gt;         bool operator-=( TSome&& some )         {             return removeHandler( handlers::HandlerCast&lt;TSome&gt;::cast&lt;TParams...&gt;( some ) );         }      protected:          using TMyEventHandlerPtr = handlers::TEventHandlerPtr&lt;TParams...&gt;;          IEvent() {}          virtual bool isHandlerAdded( const TMyEventHandlerPtr& eventHandler ) const = 0;         virtual bool addHandler( TMyEventHandlerPtr eventHandler ) = 0;         virtual bool removeHandler( TMyEventHandlerPtr eventHandler ) = 0;      friend class joins::HandlerEventJoin&lt;TParams...&gt;; };   template&lt;class ...TParams&gt; class TEvent : public IEvent&lt;TParams...&gt; {     using TEventHandlerIt = typename std::list&lt;TMyEventHandlerPtr&gt;::const_iterator;      public:          TEvent() :             m_handlers(),             m_currentIt(),             m_isCurrentItRemoved( false ),             m_handlerListMutex()         {         }          void operator()( TParams... params )         {             m_handlerListMutex.lock_shared();                          m_isCurrentItRemoved = false;             m_currentIt = m_handlers.begin();             while( m_currentIt != m_handlers.end() )             {                 m_handlerListMutex.unlock_shared();                 ( *m_currentIt )-&gt;call( params... );                 m_handlerListMutex.lock_shared();                  if( m_isCurrentItRemoved )                 {                     m_isCurrentItRemoved = false;                      TEventHandlerIt removedIt = m_currentIt;                     ++m_currentIt;                      deleteHandler( removedIt );                 }                 else                 {                     ++m_currentIt;                 }             }              m_handlerListMutex.unlock_shared();         }      protected:          virtual bool isHandlerAdded( const TMyEventHandlerPtr& eventHandler ) const override         {             std::shared_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );              return ( findEventHandler( eventHandler ) != m_handlers.end() );          }         virtual bool addHandler( TMyEventHandlerPtr eventHandler ) override         {             std::unique_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );              if( findEventHandler( eventHandler ) == m_handlers.end() )             {                 m_handlers.push_back( std::move( eventHandler ) );                 return true;             }             return false;         }         virtual bool removeHandler( TMyEventHandlerPtr eventHandler ) override         {             std::unique_lock&lt;std::shared_mutex&gt; _handlerListMutexLock( m_handlerListMutex );              auto it = findEventHandler( eventHandler );             if( it != m_handlers.end() )             {                 if( it == m_currentIt )                     m_isCurrentItRemoved = true;                 else                     deleteHandler( it );                  return true;             }             return false;         }      private:          \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f 'm_handlerListMutex'         inline TEventHandlerIt findEventHandler( const TMyEventHandlerPtr& eventHandler ) const noexcept         {             return std::find_if( m_handlers.cbegin(), m_handlers.cend(), [ &eventHandler ]( const TMyEventHandlerPtr& oneHandler )             {                 return ( *oneHandler == *eventHandler );             } );         }         \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438 'm_handlerListMutex'         inline void deleteHandler( TEventHandlerIt it )         {             m_handlers.erase( it );         }          std::list&lt;TMyEventHandlerPtr&gt; m_handlers;          \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434 \u0437\u0430\u043b\u043e\u0447\u0435\u043d\u043d\u044b\u043c 'm_handlerListMutex'         mutable TEventHandlerIt m_currentIt;         mutable bool m_isCurrentItRemoved;          mutable std::shared_mutex m_handlerListMutex; };   } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/abstracteventjoin.h<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once   namespace events {  namespace joins {   class AbstractEventJoin {     public:          virtual ~AbstractEventJoin();          virtual bool isJoined() const = 0;         virtual bool join() = 0;         virtual bool unjoin() = 0;      protected:          AbstractEventJoin(); };   } \/\/ joins  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/abstracteventjoin.cpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#include &quot;abstracteventjoin.h&quot;   namespace events {  namespace joins {   AbstractEventJoin::AbstractEventJoin() { }  AbstractEventJoin::~AbstractEventJoin() { }   } \/\/ joins  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/handlereventjoin.h<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &quot;abstracteventjoin.h&quot; #include &quot;..\/handlers\/eventhandlerptr.h&quot;   namespace events {   template&lt;class ...TParams&gt; class IEvent;   namespace joins {   template&lt;class ...TParams&gt; class HandlerEventJoin : public AbstractEventJoin {     public:          HandlerEventJoin( IEvent&lt;TParams...&gt;& _event, ::events::handlers::TEventHandlerPtr&lt;TParams...&gt; handler ) :             AbstractEventJoin(),             m_event( _event ),             m_handler( handler )         {         }          virtual inline bool isJoined() const override;         virtual inline bool join() override;         virtual inline bool unjoin() override;      private:          IEvent&lt;TParams...&gt;& m_event;         ::events::handlers::TEventHandlerPtr&lt;TParams...&gt; m_handler; };   } \/\/ joins  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/handlereventjoin.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &quot;handlereventjoin.h&quot; #include &quot;..\/event.hpp&quot;   namespace events {  namespace joins {   template&lt;class ...TParams&gt; bool HandlerEventJoin&lt;TParams...&gt;::isJoined() const {     return m_event.isHandlerAdded( m_handler ); }  template&lt;class ...TParams&gt; bool HandlerEventJoin&lt;TParams...&gt;::join() {     return m_event.addHandler( m_handler ); }  template&lt;class ...TParams&gt; bool HandlerEventJoin&lt;TParams...&gt;::unjoin() {     return m_event.removeHandler( m_handler ); }   } \/\/ joins  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/eventjoinwrapper.h<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &lt;memory&gt; #include &quot;..\/handlers\/eventhandlerptr.h&quot;   namespace events {   template&lt;class ...TParams&gt; class IEvent;   namespace joins {   class AbstractEventJoin;   class EventJoinWrapper {     public:          template&lt;class TSome, class ...TParams&gt;         inline EventJoinWrapper( IEvent&lt;TParams...&gt;& _event, TSome&& handler );          constexpr EventJoinWrapper() noexcept;         EventJoinWrapper( EventJoinWrapper&& other ) noexcept;         EventJoinWrapper( EventJoinWrapper& other ) noexcept;          EventJoinWrapper& operator=( EventJoinWrapper&& other ) noexcept;         EventJoinWrapper& operator=( const EventJoinWrapper& other ) noexcept;          operator bool() const;          bool isAssigned() const;          bool isJoined() const;         bool join();         bool unjoin();      private:          std::shared_ptr&lt;AbstractEventJoin&gt; m_eventJoin; };   } \/\/ joins   using EventJoin = joins::EventJoinWrapper;   } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/eventjoinwrapper.hpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#pragma once  #include &quot;eventjoinwrapper.h&quot; #include &quot;handlereventjoin.h&quot; #include &quot;..\/handlers\/handlercast.hpp&quot;   namespace events {  namespace joins {   template&lt;class TSome, class ...TParams&gt; EventJoinWrapper::EventJoinWrapper( IEvent&lt;TParams...&gt;& _event, TSome&& handler ) :     m_eventJoin( std::make_shared&lt;HandlerEventJoin&lt;TParams...&gt;&gt;( _event, ::events::handlers::HandlerCast&lt;TSome&gt;::cast&lt;TParams...&gt;( handler ) ) ) { }   } \/\/ joins  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">.\/events\/joins\/eventjoinwrapper.cpp<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#include &quot;eventjoinwrapper.h&quot;  #include &lt;type_traits&gt; #include &quot;abstracteventjoin.h&quot;   namespace events {  namespace joins {   constexpr EventJoinWrapper::EventJoinWrapper() noexcept :     m_eventJoin( nullptr ) { }  EventJoinWrapper::EventJoinWrapper( EventJoinWrapper&& other ) noexcept :     m_eventJoin( std::move( other.m_eventJoin ) ) { }  EventJoinWrapper::EventJoinWrapper( EventJoinWrapper& other ) noexcept :     m_eventJoin( other.m_eventJoin ) { }   EventJoinWrapper& EventJoinWrapper::operator=( EventJoinWrapper&& other ) noexcept {     m_eventJoin = std::move( other.m_eventJoin );      return *this; }  EventJoinWrapper& EventJoinWrapper::operator=( const EventJoinWrapper& other ) noexcept {     m_eventJoin = other.m_eventJoin;      return *this; }   EventJoinWrapper::operator bool() const {     return isJoined(); }   bool EventJoinWrapper::isAssigned() const {     return ( m_eventJoin != nullptr ); }   bool EventJoinWrapper::isJoined() const {     return ( m_eventJoin != nullptr && m_eventJoin-&gt;isJoined() ); }  bool EventJoinWrapper::join() {     return ( m_eventJoin != nullptr ? m_eventJoin-&gt;join() : false ); }  bool EventJoinWrapper::unjoin() {     return ( m_eventJoin != nullptr ? m_eventJoin-&gt;unjoin() : false ); }   } \/\/ joins  } \/\/ events <\/code><\/pre>\n<p>  <\/div>\n<\/div>\n<p>  <\/div>\n<\/div>\n<p>  <a name=\"Qt\"><\/a><\/p>\n<h1>P.S. \u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u043e\u043c \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432\/\u0441\u043b\u043e\u0442\u043e\u0432 Qt<\/h1>\n<p>  \u0414\u0443\u043c\u0430\u044e, \u043d\u0435 \u043e\u0448\u0438\u0431\u0443\u0441\u044c, \u0435\u0441\u043b\u0438 \u0441\u043a\u0430\u0436\u0443 \u0447\u0442\u043e <a href=\"https:\/\/www.qt.io\/what-is-qt\/\">Qt<\/a> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0435\u0441\u044c\u043c\u0430 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u043e\u043c \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043d\u0430 <i>C++<\/i>. \u041a\u0440\u043e\u043c\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u0440\u043e\u0447\u0435\u0433\u043e, \u0435\u0441\u0442\u044c \u0432 \u043d\u0451\u043c \u0438 <a href=\"http:\/\/wiki.qt.io\/New_Signal_Slot_Syntax\">\u0441\u0432\u043e\u0439 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439<\/a>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0435\u0441\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u043a\u0430\u043a \u0430\u043d\u0430\u043b\u043e\u0433\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0438 \u0441\u043b\u043e\u0442\u044b \u043a\u0430\u043a \u0430\u043d\u0430\u043b\u043e\u0433\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432. \u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u043e\u043d \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"http:\/\/doc.qt.io\/qt-5\/moc.html\">Meta-Object Compiler&#8217;\u0430<\/a>, \u044f\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0431\u043e\u043b\u0435\u0435 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u0439 <a href=\"http:\/\/doc.qt.io\/qt-5\/metaobjects.html\">Meta-Object System<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f, \u0432 \u0441\u0432\u043e\u044e \u043e\u0447\u0435\u0440\u0435\u0434\u044c, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0432 <i>Qt<\/i> \u043d\u0430\u0434\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430\u0434 <i>\u0421++<\/i>.<\/p>\n<h4>\u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u043e\u0431\u0435\u0438\u0445 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0439:<\/h4>\n<p>  <\/p>\n<ul>\n<li>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 (\u0441\u043e\u0431\u044b\u0442\u0438\u0439) \u043a \u043c\u0435\u0442\u043e\u0434\u0430\u043c (\u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c-\u0447\u043b\u0435\u043d\u0430\u043c), \u0444\u0443\u043d\u043a\u0442\u043e\u0440\u0430\u043c \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c;<\/li>\n<li>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0441\u0438\u0433\u043d\u0430\u043b\u0443 (\u0441\u043e\u0431\u044b\u0442\u0438\u044e) \u0441\u043b\u043e\u0442\u043e\u0432 (\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432), \u0442\u0438\u043f\u044b \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0433\u0443\u0442 \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f \u0432\u0438\u0434\u043e\u043c \u0441\u0441\u044b\u043b\u043a\u0438 (<i>lvalue<\/i>, <i>rvalue<\/i>);<\/li>\n<li>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u043a \u0441\u0438\u0433\u043d\u0430\u043b\u0443 (\u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043a \u0441\u043e\u0431\u044b\u0442\u0438\u044e);<\/li>\n<li>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f (\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f) \u043f\u0440\u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 (\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u043a \u0441\u043b\u043e\u0442\u0443).<\/li>\n<\/ul>\n<p>  <\/p>\n<h4>\u041f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430 <i>Qt<\/i>:<\/h4>\n<p>  <\/p>\n<ul>\n<li> <i>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432;<\/i><br \/>   \u0432 <i>Qt<\/i> \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043a \u0441\u0438\u0433\u043d\u0430\u043b\u0430\u043c \u0441\u043b\u043e\u0442\u043e\u0432 \u0441 \u043c\u0435\u043d\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432; \u0440\u0435\u0434\u0443\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u043c\u043e\u0433\u0443\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u00ab\u0441\u043f\u0440\u0430\u0432\u0430\u00bb, \u0438\u043d\u044b\u043c\u0438 \u0441\u043b\u043e\u0432\u0430\u043c\u0438, \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u0430 \u0441\u043b\u043e\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u00ab\u043b\u0435\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438\u00bb \u0441\u0438\u0433\u043d\u0430\u0442\u0443\u0440\u044b \u0441\u0438\u0433\u043d\u0430\u043b\u0430; \u043a\u0430\u043a \u0447\u0430\u0441\u0442\u043d\u044b\u0439 \u0441\u043b\u0443\u0447\u0430\u0439, \u043a \u043b\u044e\u0431\u043e\u043c\u0443 \u0441\u0438\u0433\u043d\u0430\u043b\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u043b\u043e\u0442 \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432; \u043f\u043e\u0436\u0430\u043b\u0443\u0439, \u044d\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u043e \u0432 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432;   <\/li>\n<li> <i>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0439;<\/i><br \/>   \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <i>Qt<\/i> \u043d\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a \u043e\u0434\u043d\u043e\u043c\u0443 \u0441\u0438\u0433\u043d\u0430\u043b\u0443 (\u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430) \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0441\u043b\u043e\u0442 (\u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430); \u0442\u0430\u043a\u043e\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <a href=\"http:\/\/doc.qt.io\/qt-5\/qt.html#ConnectionType-enum\">Qt::UniqueConnection<\/a>; \u0445\u043e\u0442\u044f \u043c\u043d\u0435 \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438 \u043d\u0435 \u043d\u0440\u0430\u0432\u0438\u0442\u0441\u044f, \u043a\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0441\u0442\u043e\u0438\u0442 \u043f\u0440\u0438\u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e <i>Qt<\/i> \u0432\u0441\u0451 \u0436\u0435 \u0434\u0430\u0451\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u0430 \u0432 \u044d\u0442\u043e\u043c \u0432\u043e\u043f\u0440\u043e\u0441\u0435;   <\/li>\n<li> <i>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u043b\u043e\u0442\u0430 \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043e\u043d \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442;<\/i><br \/>   \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c <a href=\"http:\/\/doc.qt.io\/qt-5\/qt.html#ConnectionType-enum\">Qt::QueuedConnection<\/a> \u0438\u043b\u0438 <a href=\"http:\/\/doc.qt.io\/qt-5\/qt.html#ConnectionType-enum\">Qt::BlockingQueuedConnection<\/a> \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u0441\u043b\u043e\u0442\u0430 \u043a \u0441\u0438\u0433\u043d\u0430\u043b\u0443; \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u0434 \u0441\u043b\u043e\u0442\u0430 (\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430) \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u043b\u043e\u0442\u0430; \u0438\u043d\u0430\u0447\u0435 \u043e\u043d \u0431\u044b\u043b \u0431\u044b \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 (\u0441\u043e\u0431\u044b\u0442\u0438\u044f); \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u043d\u0435 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u043e \u043f\u0440\u0438 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u0430 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u0438 \u0446\u0438\u043a\u043b\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043d\u0443\u0436\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430; \u0442.\u0435. \u044d\u0442\u043e \u0431\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u043e, \u0434\u0430\u0436\u0435 \u043a\u043e\u0433\u0434\u0430 \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0438 \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u0441\u043b\u043e\u0442\u0430 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435; \u043f\u0440\u0430\u0432\u0434\u0430, \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043a\u043e\u043f\u0438\u0440\u0443\u044e\u0442\u0441\u044f.   <\/li>\n<\/ul>\n<p>  <\/p>\n<h4>\u041d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438 <i>Qt<\/i>:<\/h4>\n<p>  <\/p>\n<ul>\n<li> <i>\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043e\u0442 <a href=\"http:\/\/doc.qt.io\/qt-5\/qobject.html\">QObject<\/a>;<\/i><br \/>   \u044d\u0442\u043e \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u043e\u043c, \u043e\u0434\u043d\u0430\u043a\u043e, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044f\u0441\u044c \u043e\u0442 <i>QObject<\/i>, \u043c\u044b \u043f\u0435\u0440\u0435\u043d\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0435\u0433\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f (<a href=\"https:\/\/doc.qt.io\/qt-5\/moc.html\">\u043e\u0442\u0441\u044e\u0434\u0430<\/a>: <i>Virtual inheritance with QObject is not supported.<\/i>); \u0432 \u0440\u044f\u0434\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 \u044d\u0442\u043e, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a;   <\/li>\n<li> <i>\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 template&#8217;\u0430\u0445;<\/i><br \/>   \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u0441\u043b\u043e\u0442\u044b, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u043d \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <i>public<\/i>-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u043e\u043c <i>QObject<\/i>; \u044d\u0442\u043e \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 <i>moc&#8217;\u0430<\/i>; \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0435\u0433\u043e \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e<br \/> \n<div class=\"spoiler\"><b class=\"spoiler_title\">\u043e\u0431\u043e\u0439\u0442\u0438,<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">#include &lt;QObject&gt; class AbstractProperty : public QObject {     Q_OBJECT     protected:         AbstractProperty();     signals:         void valueChanged(); }; template&lt;class TSource&gt; class TProperty : public AbstractProperty {     public:         TProperty( const TSource& value = TSource() ) :             AbstractProperty(),             m_value( value )         {         }         const TSource& value() const         {             return m_value;         }         void setValue( const TSource& newValue )         {             if( newValue != m_value )             {                 m_value = newValue;                 emit valueChanged();             }         }     private:                 TSource m_value; }; <\/code><\/pre>\n<p>  \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0441\u0438\u0433\u043d\u0430\u043b <i>valueChanged<\/i> \u043d\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u043e\u0433\u043e (\u0430 \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e, \u0438 \u0441\u0442\u0430\u0440\u043e\u0433\u043e) \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u0438 \u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e.   <\/div>\n<\/div>\n<p>   \u043d\u043e, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u044d\u0442\u043e \u043c\u0435\u043d\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e \u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438;   <\/li>\n<li> <i>\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0434\u0435\u043a\u043b\u0430\u0440\u0430\u0446\u0438\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 \u0432 <i>.cpp<\/i>-\u0444\u0430\u0439\u043b\u0435;<\/i><br \/>   \u0438\u043d\u043e\u0433\u0434\u0430 \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0432 <i>.cpp<\/i>-\u0444\u0430\u0439\u043b\u0435, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u043d\u0435 \u00ab\u0442\u043e\u0440\u0447\u0430\u043b\u00bb \u043d\u0430\u0440\u0443\u0436\u0443, \u0438\u043b\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043f\u043e-\u0431\u044b\u0441\u0442\u0440\u043e\u043c\u0443, \u0438\u043b\u0438 \u0435\u0449\u0451 \u0434\u043b\u044f \u043a\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439; \u0442\u0430\u043a \u0432\u043e\u0442, \u0441 \u043a\u043b\u0430\u0441\u0441\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u043c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u0441\u043b\u043e\u0442\u044b (\u0441\u043b\u043e\u0442\u044b \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 (\u0443\u0436 \u0435\u0441\u043b\u0438 \u043d\u0430 \u0442\u043e \u043f\u043e\u0448\u043b\u043e, \u043f\u0440\u043e\u0441\u0442\u043e \u043a\u043b\u0430\u0441\u0441, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 <i>Q_OBJECT<\/i>)), \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f (\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0435 <i>moc&#8217;\u0430<\/i>); \u043d\u0435 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u043f\u043e\u0432\u0441\u0435\u043c\u0435\u0441\u0442\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u043e\u0441\u044c \u0438\u043b\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0431\u043e\u0439\u0442\u0438, \u043d\u043e \u0432\u0441\u0451 \u0436\u0435;   <\/li>\n<li> <i>\u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0443 \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"http:\/\/doc.qt.io\/qt-5\/qmetaobject-connection.html\">QMetaObject::Connection<\/a>;<\/i><br \/>   \u043a\u0430\u043a \u0443\u0436\u0435 \u043e\u0442\u043c\u0435\u0447\u0430\u043b\u043e\u0441\u044c \u0432\u044b\u0448\u0435, \u0432 <i>Qt<\/i> \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f (\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0438 \u0441\u043b\u043e\u0442\u0430) \u0442\u043e\u0436\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043d\u0435\u043a\u0438\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u044d\u0442\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435; \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c (\u043e\u0442\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c) \u0441\u043b\u043e\u0442 \u043e\u0442 \u0441\u0438\u0433\u043d\u0430\u043b\u0430, \u043d\u0435 \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u044f\u0441\u044c \u043e \u0442\u043e\u043c, \u043a\u0430\u043a\u043e\u0439 \u044d\u0442\u043e \u0441\u043b\u043e\u0442 \u043a\u0430\u043a\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438 \u043a\u0430\u043a\u043e\u0439 \u044d\u0442\u043e \u0441\u0438\u0433\u043d\u0430\u043b \u043a\u0430\u043a\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430; \u043e\u0434\u043d\u0430\u043a\u043e \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u043b\u043e\u0442 \u043a \u0441\u0438\u0433\u043d\u0430\u043b\u0443 \u043d\u0430\u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e, \u043a\u0430\u043a \u0438 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0433\u043e \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0438 \u0441\u043b\u043e\u0442\u0430; \u0432 <i>Qt<\/i> \u043e\u043d \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u0435\u0439 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f;   <\/li>\n<li> <i>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u043e\u0433\u043e <i>moc&#8217;\u043e\u043c<\/i> \u043a\u043e\u0434\u0430;<\/i><br \/>   \u044d\u0442\u043e \u0443\u0436\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u043e, \u043d\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u0433\u0434\u0435 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0439 \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u0441\u043b\u043e\u0442\u044b (\u0441\u043b\u043e\u0442\u044b \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430) \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e (\u043f\u043e \u0444\u0430\u0439\u043b\u0443 \u043d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e) \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430; \u043d\u043e \u0441\u043a\u0430\u0436\u0435\u043c \u0447\u0435\u0441\u0442\u043d\u043e, \u044d\u0442\u043e \u0441\u0430\u043c\u044b\u0439 \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a.   <\/li>\n<\/ul>\n<p>  \u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0441 <i>Qt<\/i> \u0432\u0441\u0451 \u0436\u0435 \u0432\u0435\u0441\u044c\u043c\u0430 \u0441\u0443\u0431\u044a\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438 \u043d\u0435 \u043d\u0430\u0446\u0435\u043b\u0435\u043d\u043e \u043d\u0430 \u043f\u0440\u0435\u0432\u043e\u0437\u043d\u0435\u0441\u0435\u043d\u0438\u0435 \u0438\u043b\u0438 \u043e\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u041d\u0443\u0436\u043d\u043e \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043a\u0440\u043e\u043c\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432\/\u0441\u043b\u043e\u0442\u043e\u0432 <i>Qt<\/i> \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0439 \u044d\u0442\u043e\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c, \u0442\u0430\u043a \u0438 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0439 \u043e\u0442 \u043d\u0435\u0433\u043e. \u0412 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0440\u0435\u0448\u0430\u0442\u044c, \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u0430 \u0447\u0442\u043e \u043d\u0435\u0442, \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u0430\u043c.<\/div>\n<p>        <script class=\"js-mediator-script\">!function(e){function t(t,n){if(!(n in e)){for(var r,a=e.document,i=a.scripts,o=i.length;o--;)if(-1!==i[o].src.indexOf(t)){r=i[o];break}if(!r){r=a.createElement(\"script\"),r.type=\"text\/javascript\",r.async=!0,r.defer=!0,r.src=t,r.charset=\"UTF-8\";var d=function(){var e=a.getElementsByTagName(\"script\")[0];e.parentNode.insertBefore(r,e)};\"[object Opera]\"==e.opera?a.addEventListener?a.addEventListener(\"DOMContentLoaded\",d,!1):e.attachEvent(\"onload\",d):d()}}}t(\"\/\/mediator.mail.ru\/script\/2820404\/\",\"_mediator\")}(window);<\/script>     <br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/post\/424593\/\"> https:\/\/habr.com\/post\/424593\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html js-mediator-article\">\u0414\u0443\u043c\u0430\u044e, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u043a\u0430\u043a \u0441\u043f\u043e\u0441\u043e\u0431 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0432 \u041e\u041e\u041f, \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u043f\u043e\u0447\u0442\u0438 \u043a\u0430\u0436\u0434\u043e\u043c\u0443, \u043a\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435 \u0445\u043e\u0442\u044c \u0440\u0430\u0437 \u043a\u0430\u0441\u0430\u043b\u0441\u044f \u041e\u041e\u041f. \u041f\u043e \u043a\u0440\u0430\u0439\u043d\u0435\u0435 \u043c\u0435\u0440\u0435, \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0432\u0435\u0441\u044c\u043c\u0430 \u0443\u0434\u043e\u0431\u0435\u043d \u0432 \u0432\u0435\u0441\u044c\u043c\u0430 \u0448\u0438\u0440\u043e\u043a\u043e\u043c, \u043d\u0430 \u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u0441\u043f\u0435\u043a\u0442\u0440\u0435 \u0437\u0430\u0434\u0430\u0447. \u0412\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u044f\u0437\u044b\u043a\u0430\u0445 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c; \u043e\u0434\u043d\u0430\u043a\u043e \u0432 C++ \u0442\u0430\u043a\u043e\u0433\u043e \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u043d\u0435\u0442. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441 \u044d\u0442\u0438\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-289982","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/289982","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=289982"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/289982\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=289982"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=289982"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=289982"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}