{"id":260579,"date":"2015-07-02T14:58:02","date_gmt":"2015-07-02T10:58:02","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=260579"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=260579","title":{"rendered":"Compile-time \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u044f D, \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0430"},"content":{"rendered":"<p>     \t\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a, \u0445\u0430\u0431\u0440!<\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 <a href=\"http:\/\/habrahabr.ru\/post\/261349\/\">\u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u0431\u044b\u043b\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b compile-time \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438, \u0442\u0435 \u043a\u0438\u0440\u043f\u0438\u0447\u0438\u043a\u0438, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u044f\u0442 \u00ab\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435\u00bb \u043c\u0435\u0442\u0430\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u0438\u0451\u043c\u044b. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u0441\u043b\u043e\u0442\u044b, \u043f\u043e\u0445\u043e\u0436\u0438\u0435 \u043d\u0430 \u0442\u0435, \u0447\u0442\u043e \u0432 Qt, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:  <\/p>\n<pre><code>class Foo : XObject {     @&#8203;signal     void message( string str ); } class Bar : XObject {     @&#8203;slot     void print( string str ) { writefln( &quot;Bar.print: %s&quot;, str ); } } void main() {     auto a = new Foo, b = new Bar;     connect( a.message, b.print );     a.message( &quot;hello habr&quot; ); \/\/ Bar.print: hello habr } <\/code><\/pre>\n<p>  \u041e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e: \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 (\u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u043c\u0438).<br \/>  <a name=\"habracut\"><\/a><br \/>  \u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e, \u043d\u043e \u043d\u0435 \u0442\u0430\u043a =) \u041d\u043e \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u043c\u0443 \u0441\u0447\u0451\u0442\u0443 \u043d\u0435 \u0445\u0443\u0436\u0435, \u043d\u0430 \u0432\u0441\u0451 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u044b, \u043c\u044b \u043e \u043d\u0438\u0445 \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c. \u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442:  <\/p>\n<pre><code>class Foo : XObject {     mixin MixX; \/\/ \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043a\u043e\u0434, \u0431\u0435\u0437 mixin \u043d\u0435 \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c     @&#8203;signal     void _message( string str ) {} \/\/ \u0434\u043e\u0441\u0430\u0434\u043d\u043e\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0441\u043c \u043d\u0438\u0436\u0435 } class Bar : XObject {     mixin MixX;      \/\/ \u043d\u0435 \u0432\u0438\u0436\u0443 \u0441\u043c\u044b\u0441\u043b\u0430 \u0432 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0435 slot, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u043e \u0441\u0443\u0442\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u043b\u044e\u0431\u043e\u0439 \u043c\u0435\u0442\u043e\u0434     void print( string str ) { writefln( &quot;Bar.print: %s&quot;, str ); } } void main() {     auto a = new Foo, b = new Bar;     connect( a.signal_message, &b.print ); \/\/ \u043e\u0431 \u044d\u0442\u043e\u043c \u043f\u043e\u0437\u0436\u0435     a.message( &quot;hello habr&quot; ); \/\/ Bar.print: hello habr } <\/code><\/pre>\n<p>  <a href=\"http:\/\/forum.dlang.org\/post\/ndyrxwkbdofmaxzwuqbb@forum.dlang.org\">\u0414\u043e\u0441\u0430\u0434\u043d\u043e\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u043e<\/a> \u0433\u043b\u0430\u0441\u0438\u0442, \u0447\u0442\u043e \u0435\u0441\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u044b\u043b\u0430 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430 \u0447\u0435\u0440\u0435\u0437 mixin \u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0430\u044f \u0436\u0435, \u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430\u044f (\u043e\u0431\u044b\u0447\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u0430\u044f), \u0442\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0447\u0435\u0440\u0435\u0437 mixin \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0443 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043d\u0435\u0442 \u0442\u0435\u043b\u0430. \u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u0442\u044c \u043f\u043e \u0441\u0443\u0442\u0438 \u0434\u0440\u0443\u0433\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441 \u0442\u0435\u043b\u043e\u043c.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0447\u043d\u0451\u043c \u043f\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0443. \u041f\u0435\u0440\u0432\u044b\u043c \u0434\u0435\u043b\u043e\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u043e\u0437\u043d\u0430\u0442\u044c, \u0447\u0442\u043e \u043f\u043e\u0434\u0445\u043e\u0434 \u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u043e\u043c \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u0432 \u00ab\u043d\u0435 \u043e\u0447\u0435\u043d\u044c\u00bb. \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0432\u0441\u0451 \u0441\u0438\u043b\u044c\u043d\u043e \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0437\u0430\u0434\u0430\u0447\u0438. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u043c \u0441\u0447\u0438\u0442\u0430\u0442\u044c, \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0439:   <\/p>\n<ol>\n<li>\u043b\u044e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u0438 \u043d\u0435\u0442<\/li>\n<li>\u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0432\u0435\u0441\u0442\u0438 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 (\u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u043d \u0432\u0430\u043b\u0438\u0434\u0435\u043d)<\/li>\n<li>\u0443 \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b<\/li>\n<li>\u0435\u0441\u043b\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u0431\u044b\u0442\u044c \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0442\u043e\u0436\u0435 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u044e\u0442 \u0442\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u0431\u044b\u0442\u044c<\/li>\n<li>\u0432\u044b\u0437\u043e\u0432 \u0441\u043b\u043e\u0442\u043e\u0432 \u043d\u0435 \u0432\u0430\u043b\u0438\u0434\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d (\u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043c\u044b\u0441\u043b\u0430)<\/li>\n<\/ol>\n<p>  \u041f\u043e \u043b\u043e\u0433\u0438\u043a\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0442 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044e.<br \/>  \u0412 D \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u043a\u043b\u0430\u0441\u0441\u043e\u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u043e\u043c, \u0432\u044b\u0437\u043e\u0432 \u0434\u0435\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043c\u0443\u0441\u043e\u0440\u0430 \u043b\u0438\u0431\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 destroy(obj). \u0422\u0430\u043a \u0436\u0435 \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u043c\u043e\u043c\u0435\u043d\u0442: \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0430\u043c\u044f\u0442\u044c\u044e \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u043c\u0443\u0441\u043e\u0440\u0430 \u043d\u0435\u043b\u044c\u0437\u044f. \u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0443\u0431\u0440\u0430\u0442\u044c \u0438\u0437 \u043a\u0430\u043a\u043e\u0433\u043e-\u043b\u0438\u0431\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0430\u0435\u043c\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0434\u0430 \u0438 \u0441\u0431\u043e\u0440\u0449\u0438\u043a \u0441\u0430\u043c \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043f\u043e\u043a\u0430 \u043e\u0431\u044a\u0435\u043a\u0442 \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435. \u0420\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044f \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043c\u044b\u0441\u043b\u044c \u043e \u0441\u0431\u043e\u0440\u0449\u0438\u043a\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043c \u043a \u0432\u044b\u0432\u043e\u0434\u0443, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u0430 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u044f ContextHandler. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0448 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441.  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041d\u0435 \u043f\u043e\u043b\u043d\u044b\u0439, \u043d\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u0439 \u0434\u043b\u044f \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f, \u043a\u043e\u0434 ContextHandler<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code>interface ContextHandler { protected:     void selfDestroyCtx(); \/\/ \u0434\u0435\u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0441\u0430\u043c\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 public:      @&#8203;property     {         ContextHandler parentCH(); \/\/ \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044c \u043d\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f         ContextHandler[] childCH(); \/\/ \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445     }      final     {         T registerCH(T)( T obj, bool force=true ) \/\/ \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u0430\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439             if( is( T == class ) )         {             if( auto ch = cast(ContextHandler)obj )                 if( force || ( !force && ch.parentCH is null ) ) \/\/ force - \u0434\u0430\u0436\u0435 \u043f\u0440\u0438 \u043d\u0430\u043b\u0438\u0447\u0438\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f \u0443 obj \u0441\u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0430 \u0441\u0435\u0431\u044f                     ...             return obj;         }          T newCH(T,Args...)( Args args ) { return registerCH( new T(args) ); } \/\/ \u043b\u0438\u0431\u043e \u0441\u0440\u0430\u0437\u0443 \u0441\u043e\u0437\u0434\u0430\u0442\u044c          void destroyCtx() \/\/ \u0440\u0430\u0434\u0438 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u0432\u0441\u0451 \u0438 \u0437\u0430\u0442\u0435\u044f\u043d\u043e         {             foreach( c; childCH ) \/\/ \u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0435 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b                 c.destroyCtx();             selfDestroyCtx(); \/\/ \u043f\u043e\u0442\u043e\u043c \u0441\u0435\u0431\u044f         }     } } <\/code><\/pre>\n<\/div>\n<\/div>\n<p>  \u041f\u043e \u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u0434\u0435\u0440\u0435\u0432\u043e. \u041f\u0440\u0438 \u0434\u0435\u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043e\u043d \u0434\u0435\u043b\u0430\u0435\u0442 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u0441 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c\u0438. \u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u043f\u043e\u0437\u0436\u0435.<\/p>\n<p>  \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438 \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u043f\u043e\u043d\u044f\u0442\u0438\u044e \u00ab\u0441\u043b\u043e\u0442\u00bb. \u0425\u043e\u0442\u044c \u043c\u044b \u0438 \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0434\u043b\u044f \u0441\u043b\u043e\u0442\u043e\u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 UDA, \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u0430\u043a \u0442\u0430\u043a\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0442 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b.  <\/p>\n<pre><code>interface SignalConnector \/\/ \u0431\u0435\u0437\u0448\u0430\u0431\u043b\u043e\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0442 {     void disconnect( SlotContext );     void disonnectAll(); }  class SlotContext : ContextHandler \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u043b\u043e\u0442 \u0438\u043c\u0435\u0435\u0442 \u0442\u043e\u0442 \u0441\u0430\u043c\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u0442\u044c \u043d\u0435\u0432\u0430\u043b\u0438\u0434\u043d\u044b\u043c {     mixin MixContextHandler; \/\/ ContextHandler \u0438\u043c\u0435\u0435\u0442 mixin template \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 protected:     size_t[SignalConnector] signals; \/\/ \u0432\u0441\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044b, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0441\u043e\u0435\u0434\u0438\u043d\u0451\u043d \u0441\u043b\u043e\u0442 public:     void connect( SignalConnector sc ) { signals[sc]++; }     void disconnect( SignalConnector sc )     {         if( sc in signals )         {             if( signals[sc] &gt; 0 ) signals[sc]--;             else signals.remove(sc);         }     } protected:     void selfDestroyCtx() \/\/ \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0443\u0448\u0435\u043d\u0438\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0440\u0430\u0437\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0451\u043d\u043d\u044b\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044b     {         foreach( sig, count; signals )             sig.disconnect(this);     } }  \/\/ \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 interface SlotHandler { SlotContext slotContext() @property; }  class Slot(Args...) \/\/ \u043a\u0430\u043a \u0442\u0430\u043a\u043e\u0432\u043e\u0439 \u0441\u043b\u043e\u0442 { protected:     Func func; \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044f     SlotContext ctrl; \/\/ \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 public:     alias Func = void delegate(Args);     this( SlotContext ctrl, Func func ) { this.ctrl = ctrl; this.func = func; }     this( SlotHandler hndl, Func func ) { this( hndl.slotContext, func ); }     void opCall( Args args ) { func( args ); }     SlotContext context() @&#8203;property { return ctrl; } } <\/code><\/pre>\n<p>  \u0421\u0440\u0430\u0437\u0443 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0441\u0438\u0433\u043d\u0430\u043b  <\/p>\n<pre><code>class Signal(Args...) : SignalConnector, ContextHandler {     mixin MixContextHandler; protected:     alias TSlot = Slot!Args;     TSlot[] slots; \/\/ \u0432\u0441\u0451 \u0441\u043e\u0435\u0434\u0438\u043d\u0451\u043d\u043d\u044b\u0435 \u0441\u043b\u043e\u0442\u044b public:     TSlot connect( TSlot s )     {         if( !connected(s) )         {             slots ~= s;             s.context.connect(this);         }         return s;     }     void disconnect( TSlot s ) \/\/ \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c     {         slots = slots.filter!(a=&gt;a !is s).array;         s.context.disconnect(this);     }     void disconnect( SlotContext sc ) \/\/ \u0434\u0430\u0436\u0435 \u0441\u0440\u0430\u0437\u0443 \u0432\u0435\u0441\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442     {         foreach( s; slots.map!(a=&gt;a.context).filter!(a=&gt; a is sc) )             s.disconnect(this);         slots = slots             .map!(a=&gt;tuple(a,a.context))             .filter!(a=&gt; a[1] !is sc)             .map!(a=&gt;a[0])             .array;     }     void disconnect( SlotHandler sh ) { disconnect( sh.slotContext ); }     void disonnectAll() \/\/ \u0438\u043b\u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u0441\u0435 \u0441\u043b\u043e\u0442\u044b     {         slots = [];         foreach( s; slots ) s.context.disconnect( this );     }     \/\/ \u0432\u044b\u0437\u043e\u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0432\u0435\u0434\u0451\u0442 \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u0432\u044b\u0437\u043e\u0432 \u0432\u0441\u0435\u0445 \u0441\u043b\u043e\u0442\u043e\u0432     void opCall( Args args ) { foreach( s; slots ) s(args); } protected:     bool connected( TSlot s ) { return canFind(slots,s); }     void selfDestroyCtx() { disonnectAll(); } \/\/ \u0442\u0430\u043a \u0436\u0435 \u0440\u0430\u0437\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0432\u0441\u0435 \u0441\u0432\u044f\u0437\u0438 \u043f\u0440\u0438 \u0440\u0430\u0437\u0440\u0443\u0448\u0435\u043d\u0438\u0438 } <\/code><\/pre>\n<p>  \u0418, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u044b \u043f\u043e\u0434\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u043c\u0443: \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0443 XBase \u0438 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u043c\u0443 \u043a\u043b\u0430\u0441\u0441\u0443 XObject (\u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f MixX \u0438 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e). \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 XBase \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 ContextHandler \u0432\u0441\u0435\u0433\u043e \u043f\u0430\u0440\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0439, \u0441\u0430\u043c\u043e\u0435 \u0432\u0430\u0436\u043d\u043e\u0435 \u044d\u0442\u043e mixin template MixX. \u0412 \u043d\u0451\u043c \u043a\u0430\u043a \u0440\u0430\u0437 \u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432\u0441\u044f \u043c\u0430\u0433\u0438\u044f \u043c\u0435\u0442\u0430\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0432\u0441\u0435\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439. UDA @\u200bsignal \u043f\u043e\u043c\u0435\u0447\u0430\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0442\u0430\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438 \u0441\u0430\u043c\u0438\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432. \u041e\u0442 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0431\u0435\u0440\u0451\u0442\u0441\u044f \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0451: \u0438\u043c\u044f (\u0431\u0435\u0437 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043d\u0438\u0436\u043d\u0435\u0433\u043e \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f), \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 (public, protected) \u0438, \u043a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435, \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b. \u0418\u0437 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u0442\u043e\u043b\u044c\u043a\u043e @\u200asystem, \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u043c\u043e\u0433\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043b\u044e\u0431\u044b\u043c\u0438 \u0441\u043b\u043e\u0442\u0430\u043c\u0438. \u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0441\u0438\u0433\u043d\u0430\u043b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 opCall \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u0432\u0441\u0435 \u0430\u0433\u0440\u0443\u043c\u0435\u043d\u0442\u044b. \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043d\u043e\u0432\u043e\u043c \u043a\u043b\u0430\u0441\u0441\u0435, \u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0432 MixX \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u044d\u0442\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0437\u0430 \u043d\u0430\u0441. \u0417\u0430\u0447\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0441\u0438\u0433\u043d\u0430\u043b \u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442? \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u0438\u0433\u043d\u0430\u043b \u0431\u044b\u043b \u0444\u0443\u043d\u043a\u0446\u0438\u0435, \u043a\u0430\u043a \u043d\u0438 \u0441\u0442\u0440\u0430\u043d\u043d\u043e. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u044b \u0432 \u043a\u043b\u0430\u0441\u0441\u0441\u0435, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c XObject \u0438\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u043c XBase, \u0430 \u0442\u0430\u043a \u0436\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0441 \u0432\u044b\u0437\u043e\u0432\u043e\u043c \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432:  <\/p>\n<pre><code>    interface Messager { void onMessage( string ); }     class Drawable { abstract void onDraw(); } \/\/ \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0441\u0442\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b     class A : Drawable, XBase     {         mixin MixX;         this() { prepareXBase(); } \/\/ \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0432\u0441\u0451 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435         @&#8203;signal void _onDraw() {}     }     class B : A, Messager     {         mixin MixX;         @&#8203;signal void _onMessage( string msg ) {}     }     class Printer : XObject     {         mixin MixX;         void print( string msg ) { }     }      auto a = new B;     auto b = new B;     auto p = new Printer;      connect( a.signal_onMessage, &b.onMessage ); \/\/ \u0441\u043e\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0441\u0438\u0433\u043d\u0430\u043b \u0441 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u043c     connect( &p.print, b.signal_onMessage ); \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u044e connect \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c \u0432 \u0441\u0430\u043c\u043e\u043c \u043a\u043e\u043d\u0446\u0435 ... <\/code><\/pre>\n<p>  \u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a XBase. \u0411\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043a\u043e\u0434 \u043f\u043e \u0447\u0430\u0441\u0442\u044f\u043c:  <\/p>\n<pre><code>interface XBase : SlotHandler, ContextHandler { public:     enum signal; \/\/ \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 UDA, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0431\u044a\u044f\u0432\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e enum protected:     void createSlotContext();     void createSignals();      final void prepareXBase() \/\/ \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u0435 \u043a\u043b\u0430\u0441\u0441\u0430, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0435\u0433\u043e XBase     {         createSlotContext();         createSignals();     }      \/\/ XBase \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442 \u0438 SlotHandler, \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u043e\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043b\u043e\u0442\u043e\u0432     final auto newSlot(Args...)( void delegate(Args) f ) { return newCH!(Slot!Args)( this, f ); }      \/\/ \u043c\u043e\u0436\u043d\u043e \u0441\u0440\u0430\u0437\u0443 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0434\u0435\u043b\u0435\u0433\u0430\u0442 \u0441 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u043c, \u0432\u043e\u0437\u043b\u0430\u0433\u0430\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0431\u044b\u043b \u0432\u044b\u0437\u0432\u0430\u043d \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434     final auto connect(Args...)( Signal!Args sig, void delegate(Args) f )     {         auto ret = newSlot!Args(f);         sig.connect( ret );         return ret;     }      mixin template MixX()     {         import std.traits;          \/\/ \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043f\u0440\u0438\u0451\u043c\u043e\u043c \u0438\u0437 \u0421++, \u0442\u0430\u043a \u043a\u0430\u043a mixin template \u043d\u0435 \u043c\u043e\u0434\u0443\u043b\u044c, \u043c\u043e\u0436\u043d\u043e \u0438 \u043a\u043e\u043d\u0444\u043b\u0438\u043a\u0442\u044b \u0441\u043b\u043e\u0432\u0438\u0442\u044c         static if( !is(typeof(X_BASE_IMPL)) )         {             enum X_BASE_IMPL = true;              mixin MixContextHandler; \/\/ \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e ContextHandler              \/\/ \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c SlotHandler             private SlotContext __slot_context;              final             {                 public SlotContext slotContext() @&#8203;property { return __slot_context; }                 protected void createSlotContext() { __slot_context = newCH!SlotContext; }             }         }          \/\/ \u0430 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0443\u0436\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437          mixin defineSignals; \/\/ \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b          override protected         {             \/\/ \u0435\u0441\u043b\u0438 createSignal \u0435\u0449\u0451 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u0437\u043d\u0430\u0447\u0438\u0442 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437             static if( isAbstractFunction!createSignals )                 void createSignals() { mixin( mix.createSignalsMixinString!(typeof(this)) ); }             else \/\/ \u0438\u043d\u0430\u0447\u0435, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432 \u043d\u0435\u0439 \u0432\u044b\u0437\u0432\u0430\u0442\u044c createSignals \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430                 void createSignals()                 {                     super.createSignals();                      \/\/ mix.createSignalsMixinString \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438\u0437 \u0442\u0438\u043f\u0430 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0440\u043e\u043a\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044d\u0442\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0443\u0436\u0435 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f                     mixin( mix.createSignalsMixinString!(typeof(this)) );                 }         }     } ... } <\/code><\/pre>\n<p>  \u0421\u0442\u043e\u0438\u0442 \u0441\u0440\u0430\u0437\u0443 \u043e\u0433\u043e\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e mix \u044d\u0442\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0441\u043a\u043e\u043d\u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u044d\u0442\u043e \u043d\u0435 \u0441\u0430\u043c\u043e\u0435 \u0443\u0434\u0430\u0447\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043d\u043e \u043e\u043d\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043e\u0431\u044a\u0451\u043c \u0438\u043c\u0451\u043d, \u043f\u043e\u043f\u0430\u0434\u0430\u0435\u043c\u044b\u0445 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441, \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0441\u0451 \u0432 \u043d\u0443\u0436\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 (\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 XBase). \u0418 \u0440\u0430\u0437 \u0443\u0436 \u0437\u0430\u0433\u043e\u0432\u043e\u0440\u0438\u043b\u0438, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u044d\u0442\u0443 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.  <\/p>\n<pre><code>    static struct __MixHelper     {         import std.algorithm, std.array;         enum NAME_RULE = &quot;must starts with '_'&quot;;     static pure @&#8203;safe:         \/\/ \u0438\u043c\u0435\u043d\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0434\u043b\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043d\u0438\u0436\u043d\u0435\u0433\u043e \u043f\u043e\u0434\u0447\u0451\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u044f         bool testName( string s ) { return s[0] == '_'; }         string getMixName( string s ) { return s[1..$]; }                  \/\/ \u0432 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a, \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0445 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e-\u0441\u0438\u0433\u043d\u0430\u043b         string signalMixinString(T,alias temp)() @&#8203;property         {             ...         }          \/\/ \u0438\u043c\u0435\u043d\u0430 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u0441 \u0442\u0430\u043a\u043e\u0433\u043e \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u0430         enum signal_prefix = &quot;signal_&quot;;                  \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0434\u043b\u044f \u043c\u0438\u043a\u0441\u0438\u043d\u0430 \u0432 createSignals         string createSignalsMixinString(T)() @&#8203;property         {             auto signals = [ __traits(derivedMembers,T) ]                 .filter!(a=&gt;a.startsWith(signal_prefix)); \/\/ \u043e\u0442\u0431\u0438\u0440\u0430\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u0438\u043c\u0435\u043d\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u043d\u0443\u0436\u043d\u044b\u0439 \u043d\u0430\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441              \/+ \u0435\u0441\u043b\u0438 \u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 signal_ \u0432 \u0441\u0432\u043e\u0451\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432              + \u0412\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0440\u043e\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0435\u0449\u0451 \u0440\u0430\u0437 \u0441 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u043e\u0439 \u043d\u0430 \u0442\u0438\u043f              +\/              return signals                 .map!(a=&gt;format(&quot;%1$s = newCH!(typeof(%1$s));&quot;,a)) \/\/ signal_onSomething = newCH!(typeof(signal_onSomething);                 .join(&quot;\\n&quot;);             \/\/ \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432, \u043e\u043d\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u043a \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043a \u043e\u0431\u044a\u0435\u043a\u0442\u0443         }          \/\/ \u0441\u043b\u0443\u0436\u0435\u0431\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043e\u0448\u0438\u0431\u043e\u043a         template functionFmt(alias fun) if( isSomeFunction!fun )         {             enum functionFmt = format( &quot;%s %s%s&quot;,                     (ReturnType!fun).stringof, \/\/ \u0431\u0435\u0440\u0451\u043c \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u0444\u0443\u043d\u043a\u0446\u0438\u0438                     __traits(identifier,fun), \/\/ \u0435\u0451 \u0438\u043c\u044f                     (ParameterTypeTuple!fun).stringof ); \/\/ \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432         }     }      protected enum mix = __MixHelper.init; <\/code><\/pre>\n<p>  \u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a MixX, \u0432 \u043d\u0451\u043c \u0441\u0430\u043c\u044b\u043c \u0441\u043b\u043e\u0436\u043d\u044b\u043c \u0431\u0443\u0434\u0435\u0442 \u043d\u0435\u043f\u0440\u0435\u043c\u0435\u0442\u043d\u044b\u0439 mixin defineSignals.  <\/p>\n<pre><code>    \/\/ \u0432 \u043d\u0451\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u043c @&#8203;signal \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0432 defineSignalsImpl     mixin template defineSignals() { mixin defineSignalsImpl!( typeof(this), getFunctionsWithAttrib!( typeof(this), signal ) ); }      \/\/ \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u0449\u0438\u043d\u044b, \u043d\u043e \u0438\u043d\u0430\u0447\u0435 \u0442\u0430\u043a\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u043d\u0435 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c (\u0441\u043f\u0438\u0441\u043e\u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043a\u0430\u043a \u0442\u0430\u043a\u043e\u0432\u044b\u0445, \u0430 \u043d\u0435 \u0438\u043c\u0451\u043d)     mixin template defineSignalsImpl(T,list...)     {         static if( list.length == 0 ) {} \/\/ \u043a\u043e\u0433\u0434\u0430 \u043f\u0443\u0441\u0442\u043e         else static if( list.length &gt; 1 )         {             \/\/ &quot;\u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0439 \u0438 \u0432\u043b\u0430\u0441\u0442\u0432\u0443\u0439&quot;             mixin defineSignalsImpl!(T,list[0..$\/2]);             mixin defineSignalsImpl!(T,list[$\/2..$]);         }         else mixin( mix.signalMixinString!(T,list[0]) ); \/\/ \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0442\u0440\u043e\u043a\u0438, \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0438 \u043e\u0431\u044a\u0435\u043a\u0442     } <\/code><\/pre>\n<p>  \u0428\u0430\u0431\u043b\u043e\u043d getFunctionsWithAttrib \u0438 mix.signalMixinString \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0440\u0430\u0432\u043d\u043e\u0441\u0438\u043b\u044c\u043d\u044b \u043f\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c mix.signalMixinString, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0440\u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0435 \u043f\u0440\u043e __MixHelper \u044f \u0435\u0451 \u0432\u044b\u0440\u0435\u0437\u0430\u043b:  <\/p>\n<pre><code>        string signalMixinString(T,alias temp)() @&#8203;property         {             enum temp_name = __traits(identifier,temp); \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043c\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0434\u043b\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0430             enum func_name = mix.getMixName( temp_name ); \/\/ \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u043c\u044f \u0443\u0436\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438              \/\/ \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0439-\u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0440\u0430\u0437\u0440\u0435\u0448\u0451\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442 @&#8203;system             enum temp_attribs = sort([__traits(getFunctionAttributes,temp)]).array;             static assert( temp_attribs == [&quot;@&#8203;system&quot;],                     format( &quot;fail Mix X for '%s': template signal function allows only @&#8203;system attrib&quot;, T.stringof ) );              \/\/ \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043d\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430 \u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0438\u043c\u0435\u043d\u0435\u043c             static if( __traits(hasMember,T,func_name) )             {                 alias base = AT!(__traits(getMember,T,func_name)); \/\/ \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0435\u0451 \u0431\u043b\u0438\u0436\u0435                  \/\/ \u043e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u043e\u0439                 static assert( isAbstractFunction!base,                         format( &quot;fail Mix X for '%s': target signal function '%s' must be abstract in base class&quot;,                             T.stringof, func_name ) );                  \/\/ \u0438 \u0442\u0430\u043a \u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442 @&#8203;system                 enum base_attribs = sort([__traits(getFunctionAttributes,base)]).array;                 static assert( temp_attribs == [&quot;@system&quot;],                         format( &quot;fail Mix X for '%s': target signal function allows only @system attrib&quot;, T.stringof ) );                  enum need_override = true;             }             else enum need_override = false;              enum signal_name = signal_prefix ~ func_name;              \/\/ \u043f\u043e\u043c\u0438\u043c\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u0435\u0449\u0451 \u0441\u043e\u0437\u0434\u0430\u0451\u0442\u0441\u044f alias \u043d\u0430 \u043a\u043e\u0440\u0442\u0435\u0436 \u0442\u0438\u043f\u043e\u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u0430, \u0442\u0430\u043a \u043f\u0440\u043e\u0449\u0435 \u043f\u043e\u0442\u043e\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b             enum args_define = format( &quot;alias %sArgs = ParameterTypeTuple!%s;&quot;, func_name, temp_name );              enum temp_protection = __traits(getProtection,temp);               \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0441 \u0442\u043e\u0439 \u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c\u044e, \u0447\u0442\u043e \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f-\u0448\u0430\u0431\u043b\u043e\u043d             enum signal_define = format( &quot;%s Signal!(%sArgs) %s;&quot;, temp_protection, func_name, signal_name );                          \/\/ \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0441\u0440\u0430\u0437\u0443 \u0441 \u0442\u0435\u043b\u043e\u043c, \u0432 \u043d\u0451\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c opCall \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430             enum func_impl = format( &quot;final %1$s %2$s void %3$s(%3$sArgs args) { %4$s(args); }&quot;,                     (need_override ? &quot;override&quot; : &quot;&quot;), temp_protection, func_name, signal_name );              \/\/ \u043d\u0435 \u0437\u043d\u0430\u044e \u0437\u0430\u0447\u0435\u043c (\u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0438\u043a\u0442\u043e \u043d\u0435 \u0443\u0432\u0438\u0434\u0438\u0442), \u043d\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0443\u0435\u043c \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a             return [args_define, signal_define, func_impl].join(&quot;\\n&quot;);         } <\/code><\/pre>\n<p>  \u0412\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043a \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044e \u0441\u043f\u0438\u0441\u043a\u0430 \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439.  <\/p>\n<pre><code>    template getFunctionsWithAttrib(T, Attr)     {         \/\/ &lt;b&gt;\u0412\u0410\u0416\u041d\u041e&lt;\/b&gt;: \u043c\u044b \u0431\u0435\u0440\u0451\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u043f\u043e\u043b\u044f \u0438 \u043c\u0435\u0442\u043e\u0434\u044b, \u0447\u0442\u043e \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u044b \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 T         \/\/ \u043a\u0430\u043a \u0440\u0430\u0437 \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430         alias getFunctionsWithAttrib = impl!( __traits(derivedMembers,T) );          enum AttrName = __traits(identifier,Attr);          \/\/ \u0432 std.typetuple \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u044e\u0449\u0438\u0435 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u043a\u043e\u0440\u0442\u0435\u0436\u0430\u043c\u0438 \u0442\u0438\u043f\u043e\u0432         \/\/ \u0442\u0430\u043a\u043e\u0439 \u0448\u0430\u0431\u043b\u043e\u043d \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 staticMap \u0438\/\u0438\u043b\u0438 anySatisfy         template isAttr(A) { template isAttr(T) { enum isAttr = __traits(isSame,T,A); } }          \/\/ \u0438 \u043e\u043f\u044f\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c         template impl( names... )         {             alias empty = TypeTuple!();              static if( names.length == 1 )             {                 enum name = names[0];                  \/\/ \u043d\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 __traits(derivedMembers,T) \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c alias,                 \/\/ \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0435\u043a\u043e\u0435 this \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0435\u0433\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c                 static if( __traits(compiles, { alias member = AT!(__traits(getMember,T,name)); } ) )                 {                     \/\/ \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u043d\u0435\u043b\u044c\u0437\u044f \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c alias some = __traits(...)                     \/\/ \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u043e\u0439 \u0445\u0430\u043a template AT(alias T) { alias AT = T; }                     alias member = AT!(__traits(getMember,T,name));                                          \/\/ \u0442\u0430 \u0436\u0435 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f, \u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0443\u0436\u0435 \u043d\u0435 \u043e\u0434\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435                     alias attribs = TypeTuple!(__traits(getAttributes,member));                      \/\/ \u0435\u0441\u043b\u0438 \u0445\u043e\u0442\u044c \u043e\u0434\u0438\u043d \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0443\u0436\u043d\u044b\u043c \u043d\u0430\u043c                     static if( anySatisfy!( isAttr!Attr, attribs ) )                     {                         enum RULE = format( &quot;%s must be a void function&quot;, AttrName );                          \/\/ \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043b\u0438 \u044d\u0442\u043e \u0432\u043e\u043e\u0431\u0449\u0435                         static assert( isSomeFunction!member,                                 format( &quot;fail mix X for '%s': %s, found '%s %s' with @%s attrib&quot;,                                     T.stringof, RULE, typeof(member).stringof, name, AttrName ) );                          \/\/ \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0441\u0438\u0433\u043d\u0430\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e void                         static assert( is( ReturnType!member == void ),                                 format( &quot;fail mix X for '%s': %s, found '%s' with @%s attrib&quot;,                                     T.stringof, RULE, mix.functionFmt!member, AttrName ) );                          \/\/ \u0438\u043c\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438-\u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441 _                         static assert( mix.testName( name ),                                 format( &quot;fail mix X for '%s': @%s name %s&quot;,                                     T.stringof, mix.functionFmt!member, AttrName, mix.NAME_RULE ) );                          alias impl = member; \/\/ \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u043c\u044b \u043c\u043e\u0436\u0435\u043c &quot;\u0432\u0435\u0440\u043d\u0443\u0442\u044c&quot; \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442                     }                     else alias impl = empty;                 }                 else alias impl = empty;             }             else alias impl = TypeTuple!( impl!(names[0..$\/2]), impl!(names[$\/2..$]) );         }     } <\/code><\/pre>\n<p>  \u041f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u043c\u043e\u0436\u043d\u043e \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438 \u0431\u043e\u043b\u044c\u0448\u0435, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<p>  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e connect. \u041e\u043d\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0441\u0442\u0440\u0430\u043d\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430 \u0444\u043e\u043d\u0435 \u043c\u0435\u0442\u0430\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f:  <\/p>\n<pre><code>void connect(T,Args...)( Signal!Args sig, T delegate(Args) slot ) {     auto slot_handler = cast(XBase)cast(Object)(slot.ptr); \/\/ \u043f\u043e \u0441\u0443\u0442\u0438 \u044d\u0442\u043e \u0433\u0440\u044f\u0437\u043d\u044b\u0439 \u0445\u0430\u043a     enforce( slot_handler, &quot;slot context is not XBase&quot; );      \/\/ \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043b\u043e\u0442\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043b\u044e\u0431\u0430\u044f \u0444\u0443\u043d\u043a\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u0435\u0441\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043d\u0435 void     static if( is(T==void) ) slot_handler.connect( sig, slot );     else slot_handler.connect( sig, (Args args){ slot(args); } ); } void connect(T,Args...)( T delegate(Args) slot, Signal!Args sig ) { connect( sig, slot ); } <\/code><\/pre>\n<p>  \u041f\u043e\u0447\u0435\u043c\u0443 \u044f \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u043b \u0442\u0430\u043a\u043e\u0439 \u0445\u0430\u043a \u0438 \u0434\u043b\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0430? \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c connect \u043a\u0430\u043a \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0441\u0442\u0430\u0442\u044c\u0438:  <\/p>\n<pre><code>    connect( a.message, b.print ); <\/code><\/pre>\n<p>  \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u0432 \u0442\u0430\u043a\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0438 \u0441\u043b\u043e\u0442\u0430, \u0447\u0442\u043e \u043f\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u043c\u0443 \u0441\u0442\u043e\u0438\u043b\u043e \u0431\u044b \u043e\u0442\u0440\u0430\u0437\u0438\u0442\u044c \u0432 \u0438\u043c\u0435\u043d\u0438. \u041d\u043e \u0441\u0430\u043c\u0430\u044f \u0432\u0430\u0436\u043d\u0430\u044f \u043f\u0440\u0438\u0447\u0438\u043d\u0430: \u0442\u0430\u043a \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f. \u0422\u0430\u043a\u0430\u044f \u0444\u043e\u0440\u043c\u0430  <\/p>\n<pre><code>void connect!(alias sig, alias slot)() ... <\/code><\/pre>\n<p> \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, alias \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 \u043f\u043e \u0441\u0443\u0442\u0438 Class.method \u0433\u0434\u0435 Class \u044d\u0442\u043e \u0438\u043c\u044f \u043a\u043b\u0430\u0441\u0441\u0430, \u0430 \u043d\u0435 \u043e\u0431\u044a\u0435\u043a\u0442. \u0418 \u043d\u0443\u0436\u043d\u043e \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u0434\u043e\u043f. \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0430\u0433\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u0430 \u0438 \u0441\u043b\u043e\u0442\u0430. \u0410 \u0444\u043e\u0440\u043c\u0430 \u0441 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430\u043c\u0438  <\/p>\n<pre><code>void connect(T,Args...)( void delegate(Args) sig, T delegate(Args) slot ) { ... } \/\/ \u0434\u043b\u044f \u0442\u0430\u043a\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430 connect( &a.message, &b.print ); <\/code><\/pre>\n<p> \u0442\u0435\u0440\u044f\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u043b\u0430\u0441\u0441\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0441\u0438\u0433\u043d\u0430\u043b. \u042f \u043d\u0435 \u043d\u0430\u0448\u0451\u043b \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 (sig.funcptr) \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0435\u0451 \u0438\u043c\u044f, \u0434\u0430 \u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u043b\u043e \u0431\u044b \u044d\u0442\u043e \u0443\u0436\u0435 \u0432 runtime, \u0430 \u0438\u043c\u044f \u0441\u0438\u0433\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043a\u0430\u043a-\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0430 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0437 \u0441\u043b\u043e\u0432\u0430\u0440\u044f (SignalConnector[string]) \u043d\u0435 \u043e\u0447\u0435\u043d\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u043e \u0431\u044b. \u041f\u043e \u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0442\u0430\u043a \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e =)<\/p>\n<p>  \u041a\u043e\u0434 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/deviator\/xobj\">github<\/a> \u0438 \u043a\u0430\u043a \u043f\u0430\u043a\u0435\u0442 <a href=\"http:\/\/code.dlang.org\/packages\/xobj\">dub<\/a>.     \t<\/p>\n<div class=\"clear\"><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"http:\/\/habrahabr.ru\/post\/261641\/\"> http:\/\/habrahabr.ru\/post\/261641\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>     \t\u0414\u043e\u0431\u0440\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0443\u0442\u043e\u043a, \u0445\u0430\u0431\u0440!<\/p>\n<p>  \u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 <a href=\"http:\/\/habrahabr.ru\/post\/261349\/\">\u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u0431\u044b\u043b\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b compile-time \u0440\u0435\u0444\u043b\u0435\u043a\u0441\u0438\u0438, \u0442\u0435 \u043a\u0438\u0440\u043f\u0438\u0447\u0438\u043a\u0438, \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0442\u0440\u043e\u044f\u0442 \u00ab\u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435\u00bb \u043c\u0435\u0442\u0430\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0445\u043e\u0447\u0443 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0430\u043a\u0438\u0435 \u043f\u0440\u0438\u0451\u043c\u044b. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u0441\u043b\u043e\u0442\u044b, \u043f\u043e\u0445\u043e\u0436\u0438\u0435 \u043d\u0430 \u0442\u0435, \u0447\u0442\u043e \u0432 Qt, \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:  <\/p>\n<pre><code>class Foo : XObject {     @&#8203;signal     void message( string str ); } class Bar : XObject {     @&#8203;slot     void print( string str ) { writefln( &quot;Bar.print: %s&quot;, str ); } } void main() {     auto a = new Foo, b = new Bar;     connect( a.message, b.print );     a.message( &quot;hello habr&quot; ); \/\/ Bar.print: hello habr } <\/code><\/pre>\n<p>  \u041e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e: \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 (\u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u043c\u0438).  <\/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-260579","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/260579","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=260579"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/260579\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=260579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=260579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=260579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}