<?xml version='1.0' encoding="utf-8"?>
      <rss version='2.0'>
      <channel>
      <title>Форум на Исходниках.RU</title>
      <link>https://forum.sources.ru</link>
      <description>Форум на Исходниках.RU</description>
      <generator>Форум на Исходниках.RU</generator>
  	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777016</guid>
        <pubDate>Wed, 29 Aug 2018 02:25:42 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777016</link>
        <description><![CDATA[Qraizer: <strong class='tag-b'>Flex Ferrum</strong>, сырцы и тут есть. Бери на здоровье. Мне до конца этой недели ещё много что успеть надо по тестовому окружению для MPC5200 под Rational Test Realtime, иначе по голове получу. И ещё было бы очень неплохо хотя бы начать для MFC5485, ибо шароварная лицензия кончается, а дальше &#036;5000.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777015</guid>
        <pubDate>Wed, 29 Aug 2018 02:16:38 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777015</link>
        <description><![CDATA[Qraizer: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=413422&view=findpost&p=3777011'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2018-08-28T19:07:08+00:00">28.08.18, 19:07</time></span><div class='quote '>Думаете всё? Как бы не так.</div></div>Когда я попытался представить себе, как всё это безобразие теперь использовать, я просто запутался в этих массивах массивов, ссылающихся на массивы, индексируемые номером из RTTI мультиметода, который ещё надо найти по RTTI-записям классов. У меня получилось не то что 4 обращения в память, там и десяток легко получался. Но тут – внезапно – я вспомнил, что RTTI-записи можно брать сразу с параметров, в результате чего тип дополнительного поля в RTTI класса можно просто заменить на порядковый номер в его иерархии и напрямую использовать для индексации массивов.<br>
Тут покумекать оказалось проще. В результате получилось примерно следующее:<ol class="tag-list" type="1"><li>идём по заполненному компоновщиком адресу к RTTI мультиметода и вычитываем оттуда указатель на первое измерение многомерной диспетчерной таблицы;</li><li>берём первый параметр, лезем к его VMT, оттуда к RTTI, откуда берём его индекс в его иерархии;</li><li>индексируем первое измерение таблицы и получаем ссылку на следующее;</li><li>повторяем пункты 2 и 3 до исчерпания динамически связываемых параметров;</li><li>конечная ссылка будет являться искомым адресом (возможно) перекрытого базового мультиметода.</li></ol>Внезапно я получил те же 4 обращения в память на каждый полиморфный параметр, и не менее внезапно оказалось, что сами мультиметоды ни в каких RTTI не нуждаются, достаточно, чтобы компоновщик по extern-ссылке сразу разместил адрес первого измерения его таблицы. Ну, скорее всего ещё одно обращение займёт собственно полиморфный вызов целевого метода, т.к. для предоставления релоков загрузчику ОС без штрафов для приложения из-за copy-on-write из read only кодовых секций в файл подкачки скорее всего эти вызовы, как обычно, будут осуществляться через переходники. Итого ровно 4k+1. Я с усилием почухал тыковку и вынужден был признать, что в документе всё верно. Но это при условии, что классы в иерархии действительно можно однозначно и непротиворечиво, несмотря ни на какие раздельные компиляции, перенумеровать, и похоже, что это так, ибо в конце концов нумерацию так же можно поручить компоновщику. Плюс этот вариант потребует больше статичных данных, генерируемых компилятором, которые к тому же создают бо́льшую нагрузку на кеш из-за меньшей корреляции обращений к памяти, но это ИМХО мелочи.<br>
Т.о. я подтвердил своё первое впечатление, что мой метакод фактически реализует тот же алгоритм (только по-другому: вместо генерации многомерных таблиц он итерационно-рекурсивно генерирует код, на лету вычисляющий элементы этой таблицы), а значит действительно работает максимально близко к идеалу. Улучшить его ещё сильнее можно лишь заменой кода на данные, т.е. этой самой нативной реализацией мультиметодов, что средствами настоящего Стандарта языка, включительно C++20, т.е. без спец.поддержки со стороны инструментальных средств разработки, невозможно. Заодно это сможет существенно сэкономить ресурсы, т.к. данные займут меньше места в исполняемом модуле, чем код, но вот на предмет производительности я бы не был так категоричен, ибо код, генерируемый бы компилятором в нативной реализации, вряд ли был бы проще кода, генерируемого моим метакодом, конечно при условии включённой оптимизации, а т.к. у меня обращений к памяти нет совсем, то два полиморфных вызова супротив 4 обращений уж как-нибудь поборются. Настало время для исключительной гордости. Причём это относится и к версии C++03. (Тут должны быть шампанское, чепчики, персидский ковёр, танец живота, араб с опахалом, кальян и фейерверк, но нужного смайла я почему-то не нашёл.)<br>
В заключение хочется сказать ещё об одном нюансе. Мои размышлизмы касательно возможной реализации мультиметодов в языке привели меня к другому методу, нежели описан в документе. И тот, что описан, мне не понравился. Зато там описываются ковариантные возвращаемые типы и рассмотрена динамическая линковка. Над первыми мне было лень думать, я успокоил себя тем, что ковариантность по факту скорее сахар, чем лютое удобство, ибо в реальном позднем связывании всё равно придётся опираться на базовые интерфейсы, а ежели уверен в возврате чего-то от него производного, static_cast&lt;&gt; выручит. А если не уверен, то dynamic_cast&lt;&gt;. А с импортом из DLLек и SOшек, увы, по-любому будут проблемы, ибо шаблоны, без extern если, крайне сложно себе представить вот так импортируемыми. Но что меня по-настоящему удивило, так что неупоминание там кастов this к заявленным в перекрытиях типам. (Ну или я плохо искал.) Ведь запросто может оказаться так, что восстановленный динамический тип не будет совпадать с типом аргумента most viable сигнатуры, и его придётся кастить. Поэтому я подозреваю, что при больших иерархиях и разумно среднем количестве перекрытий базовой сигнатуры подавляющее большинство выбираемых из таблицы целевых адресов будут уникальны и вести к прокси, который будет кастить настоящий this каждого динамически связываемого параметра к типу аргумента, указанному в сигнатуре, которая в итоге выбрана. Сейчас компиляторы тоже это делают, если некий виртуальный метод в очередном производном классе не перекрыт, но там достаточно это сделать один раз, т.к. this тоже один, а тут подобных переходников можно ожидать в весьма немалом количестве, ибо возможных комбинаций this, увы, геометрическое от -арности мультиметода и величин полиморфных иерархий количество. Это может вполне себе так некисло сравнять объёмы предположительного нативного кода и моего.<br>
<br>
Ну, пожалуй, на этом остановлюсь. Фух, хоть на диссертацию подавай.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777013</guid>
        <pubDate>Tue, 28 Aug 2018 19:17:53 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777013</link>
        <description><![CDATA[Flex Ferrum: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=413422&view=findpost&p=3777011'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2018-08-28T19:07:08+00:00">28.08.18, 19:07</time></span><div class='quote '>Блин, я всё тему никак не закончу, а вы меня хотите озадачить ещё и тамошними проблемами с публикацией, оформлением</div></div><br>
Да к чёрту перевод текста и его оформления для GitHub. Ты исходники положи. :)]]></description>
        <author>Flex Ferrum</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777011</guid>
        <pubDate>Tue, 28 Aug 2018 19:07:08 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3777011</link>
        <description><![CDATA[Qraizer: Блин, я всё тему никак не закончу, а вы меня хотите озадачить ещё и тамошними проблемами с публикацией, оформлением и переводом этого опуса и коментов в коде. У меня там даже учётки нет.<br>
Короче. Надо-таки закончить, бо новые полгода на горизонте.<br>
<br>
Открыл я, значица, тот документ. Первое, что меня удивило, что там хоть и говорится о мультиметодах, но термин используется особый: &quot;открытые мультиметоды&quot;. Как бы ну и ладно, какая разница, как называть, главное, чтоб работало, как задумано. Потом я нашёл причину уточнения: оказывается, &quot;открытые&quot; подчёркивает тот факт, что перекрываемые сигнатуры мультиметода и сам мультиметод являются свободными функциями, тогда как в классическом понимании мультиметодов они подразумеваются быть методами классов. Всего-то. Честно говоря, я вообще не понял фишки, ибо сразу отклонил идею реализовывать свои мультиметоды в контексте классов, связанных с типами его параметров. Просто потому, что мультиметод не может быть однозначно соотнесён с каким-то конкретным классом, если типы его динамических параметров принадлежат разным иерархиям, поэтому и делать его методом какого-либо из классов, являющихся каким-либо его параметром, неправильно или тогда уж делать его методом сразу всех таких классов, что ещё больше сбивает с толку, не говоря уже о сложности реализации сего. Собственно поэтому вы видите здесь отдельную структурку со статическими методами apply(), но не только поэтому. Ещё и потому, что, во-первых, как-то инкапсулировать конкретный мультиметод с его перекрытиями очень даже полезно, особенно, если таких мультиметодов в программе несколько, во-вторых, так воистину удобно передавать диспетчеру сразу весь комплект сигнатур, связанных единой зависимостью и борющихся за звание &quot;most viable&quot; в неком конкретном вызове, чтобы при этом ещё и ничего лишнего не цеплялось: вызывается чётко нужный диспетчер, и он работает с чётким фиксированным набором сигнатур.<br>
Ок, отметил я, мне плюсик, ибо даже open multi-methods тут оказались неидеальны, и за счёт открытости теряют в инкапсуляции. Причём в сравнительном анализе там далее указывается, что ...э-э-э, классические, назовём их так, мультиметоды тут могут дать фору в производительности открытым, т.к. сразу готовы быть завязаны на свою VMT, а значит смещения в таблицах будут известны в компайл-тайм, тогда как открытым придётся это разруливать в ран-тайм, но достигается это сильной связью множественной диспетчеризации с определениями участвующих в ней классов, что здорово бьёт по удобству практического использования и на простоте модификации и расширяемости, ибо таковы свойства любой сильной связи между сущностями. И снова плюсик, на этот раз в сравнении с классическими мультиметодами, т.к. у меня даже Visitor не имеет сильных связей между классами как своей иерархии, так и других (хотя и имеет такую с самим диспетчером, пережить это куда проще, ибо связь всегда к нему одному вместо целого графа перекрёстных связей между кучей классов). А RTTI так вообще никаких связей не имеет (только с инструментами самого языка, которые и так есть и никуда не денутся и без всяких мультиметодов).<br>
Идём далее. Затем идёт разбор, как именно предлагается построить диспетчеризацию, и как для этого должны быть модифицированы компилятор и компоновщик. Тут я к своему удивлению не нашёл никаких знаковых отличий от своей реализации. Т.е. вот вообще, если отвлечься от способа реализации, алгоритмы, можно сказать, совпадают. И я, и они, предлагают строить таблицы, проходя по которым, сгенерированный компилятором код будет выбирать те или иные очередные массивы, которые итерационно в итоге дадут ему чёткий указатель на конкретный открытый ...э-э-э, мульти-метод. Только у них это готовые таблицы с готовыми смещениями, и компилятор генерирует код, который выполняет косвенно-косвенно-косвенно-косвенную – формула 4k + 1 их собственная, я её не выдумывал – их поочерёдную индексацию, у меня же это код, который обходится без таблиц... но точно так же генерируется компилятором, разве что по не заранее прошитым в нём алгоритмам, когда (и если) открытые мультиметоды будут аппрувлены, а по описанному мной метаалгоритму, и его сложность всего 2k – вдвое эффективнее, если обращения к памяти приравнять к виртуальным вызовам (что естественно не так, однако особенности кеширования данных и кода (аккумулятивно) их в этом показателе уравнивают). Естественно, последний менее экономичен в плане объёма кода, зато их метод менее экономичен в плане объёма данных, и если данные соптимизировать очень сложно, они сами об этом и пишут в контексте двупараметрического visit-диспетчера, называемого «C++ Visitor» (кстати, <strong class='tag-b'>Flex Ferrum</strong>, не его ли ты слямзил для той давней Холиварной темы?), тогда как код компиляторы оптимизировать умеют неплохо уже... э-э-э, вчера. Ну что, снова плюсик? Думаю, что да. Если эффективность тут и не на моей стороне, то по крайне мере она близка к идеалу, насколько это только возможно. Это я про Visitor, конечно, с RTTI дела не так радужно.<br>
Наконец, общий объём ресурсов. Тут я должен признаться, что был несколько озадачен. Я как-то не особо вижу, что бы им удалось влезть в то бутылочное горло, которое так радужно нарисовали: 4k + 1 обращений в память + 1 виртуальный вызов. Возможно, это только предварительная оценка на случай диспетчеризации одного единственного мультиметода. Попробую коротко описать ход своих мыслей. Понятно, что коли есть языковая нативная поддержка, никаких visitor-ов не требуется, всё можно подготовить заранее. Вот только где? Первая мысль – заимплементить поле в VMT. В этом варианте я столкнулся с проблемой, что т.о., во-первых, теряется обратная бинарная совместимость с существующими библиотеками, которые – все&#33; – придётся пересобирать, во-вторых, из-за того, что компилятор не может знать заранее, будет ли конкретный класс выступать целью множественной диспетчеризации и используются ли мультиметоды в программе вообще, выходит, что он на всякий случай должен будет всегда предполагать такое использование, а значит нарушается принцип нулевой стоимости. И это особенно обидно, т.к. мультиметоды ожидаемо будут использоваться нечасто. Выходит, что VMT не самое подходящее место. К счастью есть более подходящий кандидат: RTTI-запись для него. В VMT уже есть поле для ссылки на неё, а в самой записи предусмотреть ещё одно поле не будет проблемой. Любая реализация может сохранить бинарную совместимость со своими предыдущими версиями, т.к. новая запись может быть расположена тупо в конце имеющейся своей implementation defined реализации std::type_info, а в отличие от  записей в VMT-таблице RTTI-записи не обязаны собираться в массив; и кроме того, принцип нулевой стоимости потенциально может остаться быть соблюдённым, т.к. ни разу не будучи востребованным, это поле легко удаляется линкером, ибо все COMDAT-записи у него перед глазами (это при условии, конечно, что RTTI-записи действительно лежат в секциях COMDAT, но с другой стороны, а где ещё хранить статичную информацию, которая может быть сгенерирована компилятором в разных единицах трансляции, но в итоговой программе должна быть в единственном экземпляре, ибо ровно для этого COMDAT и предназначены).<br>
Ок, говорю, но что дальше? Хватит ли одного поля? Конечно, нет, хранить нужно много всякого, но это поле будет служить лишь ссылкой. Куда? Хороший вопрос. Начнём с того, что мультиметодов в программе может быть много, а класс может входить в сигнатуру любого из них да ещё и не по разу. Отсюда следует, что нужно отдельно хранить таблицу, описывающую сами мультиметоды и ещё как-то их идентифицировать, и отдельно вон те самые массивы косвенно-косвенно-косвенно...й индексации. Ну, с идентификацией мультметодов всё просто, для них просто имеются свои RTTI-записи... сложность лишь в том, что такая таблица тоже должна быть одна на всю программу, но собираться по частям из разных единиц трансляции. Но похожая проблема уже решена на примере VMT, так что можно поручить компоновщику формирование итогого массива описаний мультиметодов, а в коде, обращающимся к записям конкретных мультеметодов, навтыкать extern-ссылок, чтоб он заполнил их конкретными адресами. Ок, а дальше? А дальше формат данных в RTTI-записи для мультиметода чётко расскажет, RTTI каких (базовых) классов ожидаются в каждом параметре (статически связываемые параметры не исключение, просто для них всегда всего один вариант выбора, подготавливаемый ещё при компиляции), а вот уже та самая новая ссылка в RTTI-записи классов должна указывать на... хи-хи, массив. Да, массив. Загляните в документ ещё раз. Там предусмотрена многомерная таблица, на пересечении всех измерений которой находится указатель на нужное перекрытие. Количество измерений таблицы равно количеству динамически связываемых параметров. (Ничего не напоминает?) А индексация выполняется посредством явных ссылок друг на друга. (Конечно напоминает, так же работает мой алгоритм.) Но вот беда: мультметодов не один, их потенциально много. Значит что? Правильно: вместо явных ссылок на следующее измерение должны быть ссылки на массивы, а вот их элементы уже будут ссылаться на следующие измерения. Т.о. массив, на который ссылается RTTI-запись класса, должен быть ещё как-то индексирован чем-то, что определяется RTTI-записью мультиметода плюс номером его параметра. Ну, с первым всё понятно, их несложно просто пронумеровать в самой же сводной таблице мультиметодов, а вот с номером параметра ...и тут оказалось, что с ним ничего не надо делать, т.к. если даже некий класс (точнее, содержащая его иерархия) будет входить параметром в некий мультиметод более одного раза, то разные такие параметры конфликтовать не будут, т.к. всё равно представлены разными срезами таблицы диспетчеризации.<br>
<br>
Думаете всё? Как бы не так.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776979</guid>
        <pubDate>Tue, 28 Aug 2018 09:43:53 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776979</link>
        <description><![CDATA[Flex Ferrum: Крайзер, свуай мультиметоды в github. Они мне понадобились в проекте. :)]]></description>
        <author>Flex Ferrum</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776583</guid>
        <pubDate>Mon, 20 Aug 2018 19:48:38 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776583</link>
        <description><![CDATA[Flex Ferrum: Тут как бы ещё какой момент. Во-первых, каких-либо особых правил оформления проектов там нет. Ну, за исключением желательности ReadMe.md и необходимости лицензии. А бенифитов - куча. Исходники удобно смотреть, комментировать, скачивать. Захочу затащить в свой проект - просто сделаю репу сабмодулем. Это просто. :) Захочу - форкну к себе и докручу что-нибудь. И всё это гораздо проще, чем возиться с zip-архивами. <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2018-08-20T19:49:50+00:00">20.08.18, 19:49</time></span></span><br>
Это потом уже (при желании) можно навтыкать всяких трависов, кодаси и прочих полезных сервисов. Но совсем не обязательно.]]></description>
        <author>Flex Ferrum</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776579</guid>
        <pubDate>Mon, 20 Aug 2018 18:22:27 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776579</link>
        <description><![CDATA[JoeUser: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=413422&view=findpost&p=3776574'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2018-08-20T17:00:25+00:00">20.08.18, 17:00</time></span><div class='quote '>Ты шутишь, надеюсь?</div></div><br>
Это очень серьезно&#33;&#33;&#33;<br>
Пилить в гитхабе прожект с демками и скриптами сборки - это по-человечески&#33;&#33;&#33;]]></description>
        <author>JoeUser</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776577</guid>
        <pubDate>Mon, 20 Aug 2018 18:09:18 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776577</link>
        <description><![CDATA[OpenGL: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=413422&view=findpost&p=3776574'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2018-08-20T17:00:25+00:00">20.08.18, 17:00</time></span><div class='quote '> Во-первых, тут полно белых ниток, и лень доводить до мировых стандартов качества. Может у кого-то его навалом, или ему за это платят, кодят де boost люди, но у меня на это нет мотивации. Во-вторых, где я найду время оформить по правилам гитхаба?</div></div>Да брось, какие там правила? :) Выкладываешь код как есть, пишешь в Readme ссылку на эту тему, создаёшь issue с заголовком &quot;перенести описание с исходников на гитхаб&quot; и ждёшь пулл реквестов :D Наверняка даже переведут на английский, если действительно хорошая реализация и на английском подобного материала не найдёшь.]]></description>
        <author>OpenGL</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776576</guid>
        <pubDate>Mon, 20 Aug 2018 17:46:45 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776576</link>
        <description><![CDATA[Qraizer: Теперь самое время вернуться к началу. Давайте для затравки я приведу выжимку из отчётов testTimeVisit и testTimeRTTI на Intel Core i3-2100, x86 mode. Тут чем медленнее процессор, тем лучше видно, на i7, к примеру, интрузивный отчёт пестрит нулями.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#62;testTimeRTTI.exe</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 10925</div><div class="code_line">1 returned: 662</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1987</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1655</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 993</div><div class="code_line">1 returned: 331</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1324</div><div class="code_line">1 returned: 662</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1655</div><div class="code_line">1 returned: 662</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 993</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1324</div><div class="code_line">1 returned: 331</div><div class="code_line">&nbsp;</div><div class="code_line">...</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 993</div><div class="code_line">1 returned: 662</div><div class="code_line">Triple D23-B1 -D21 Dispatch: 993</div><div class="code_line">5 returned: 331</div><div class="code_line">Triple D23-D13-D22 Dispatch: 1324</div><div class="code_line">7 returned: 662</div><div class="code_line">Triple D23-D11-D23 Dispatch: 993</div><div class="code_line">6 returned: 331</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1325</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple D23-B1 -D21 Dispatch: 993</div><div class="code_line">5 returned: 331</div><div class="code_line">Triple D23-D14-D22 Dispatch: 1325</div><div class="code_line">8 returned: 662</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1324</div><div class="code_line">1 returned: 662</div></ol></div></div></div></div><script>preloadCodeButtons('1');</script><br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&#62;testTimeVisit.exe</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 3642</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 1324</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 662</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 331</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 332</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 332</div><div class="code_line">&nbsp;</div><div class="code_line">...</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple D23-B1 -D21 Dispatch: 662</div><div class="code_line">5 returned: 331</div><div class="code_line">Triple D23-D13-D22 Dispatch: 331</div><div class="code_line">7 returned: 331</div><div class="code_line">Triple D23-D11-D23 Dispatch: 663</div><div class="code_line">6 returned: 331</div><div class="code_line">&nbsp;</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 331</div><div class="code_line">1 returned: 331</div><div class="code_line">Triple D23-B1 -D21 Dispatch: 662</div><div class="code_line">5 returned: 331</div><div class="code_line">Triple D23-D14-D22 Dispatch: 331</div><div class="code_line">8 returned: 331</div><div class="code_line">Triple B2 -B1 -B2 &nbsp;Dispatch: 993</div><div class="code_line">1 returned: 331</div></ol></div></div></div></div>Это Microsoft C/C++ v19.15.26726, максимальная оптимизация -O2 -GL. Даже тут видно, что время измеряется с дискретностью 331 наносекунда, и лучше не измерить, потому абсолютные результаты скорее приблизительные, но относительные вполне хорошо показательны. И это демонстрирует, что RTTI медленнее от 3-х до 6-и раз. В среднем в 4. Очень неплохой результат для такой небыстрой штуки, как бинарный поиск по сортированному массиву с ключом на std::type_info::before(). Вот примерно это после всех оптимизаций я и увидел (изначально разница была куда существеннее, раз в 15, что примерно и ожидалось) и потому решил, что гордиться Visitor-ом хоть и можно, но не особо, а особо гордиться нечем.<br>
Но. Это было первое впечатление. Потом-то я сообразил, что производительность одной отдельно взятой подсистемы RTTI на одной отдельно взятой паре иерархий классов ещё ничего не значит. Вооружившись отладчиком, полез в дебри ассемблера и улицезрел, что std::type_info::before() у Студии просто сравнивает this, и в случае неравенства делает memcmp() на чём-то типа std::type_info::name(), только замангленного. Ну да, имена классов у меня короткие, отличаются буквально на первом-третьем символе, иерархии всего в четыре-пять элементов, даже не факт, что сортировка и бинарный поиск оказались выгоднее банального линейного, который можно было несортированным построить на std::type_index. Так что пример, можно сказать, сильно перекошенный в сторону производительности для RTTI-версии. Но это моё личное мнение, тем более, что ваша реализация RTTI ещё неизвестно как устроена.<br>
Ну, с особой гордостью, как бы, дело прояснилось. Настала пора заценить повод для исключительной. А что такое исключительная в данном контексте? Правильно: насколько реализация приближается к идеалу. А что такое идеал? Правильно: это мультиметоды, поддержанные в языке нативно. Жаль только, нету её. Я вздохнул, и открыл <a class='tag-url' href='http://www.stroustrup.com/multimethods.pdf' target='_blank'>вот этот документ</a>...]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776575</guid>
        <pubDate>Mon, 20 Aug 2018 17:42:36 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776575</link>
        <description><![CDATA[Flex Ferrum: <div class='tag-quote'><a class='tag-quote-link' href='https://forum.sources.ru/index.php?showtopic=413422&view=findpost&p=3776574'><span class='tag-quote-prefix'>Цитата</span></a> <span class='tag-quote__quote-info'>Qraizer &#064; <time class="tag-quote__quoted-time" datetime="2018-08-20T17:00:25+00:00">20.08.18, 17:00</time></span><div class='quote '>Ты шутишь, надеюсь? Во-первых, тут полно белых ниток, и лень доводить до мировых стандартов качества. Может у кого-то его навалом, или ему за это платят, кодят де boost люди, но у меня на это нет мотивации. Во-вторых, где я найду время оформить по правилам гитхаба? Ты видишь, сколько времени я угробил на эти темы, а ведь тут оформления почитай-то и нет.</div></div><br>
Ты слишком высокого мнения о гитхабе. :) <br>
<br>
<span class="tag-color tag-color-named" data-value="mergepost" style="color: mergepost"><span class='tag-size' data-value='7' style='font-size:7pt;'>Добавлено <time class="tag-mergetime" datetime="2018-08-20T17:42:55+00:00">20.08.18, 17:42</time></span></span><br>
И нет, я не шучу.]]></description>
        <author>Flex Ferrum</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776574</guid>
        <pubDate>Mon, 20 Aug 2018 17:00:25 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776574</link>
        <description><![CDATA[Qraizer: Ты шутишь, надеюсь? Во-первых, тут полно белых ниток, и лень доводить до мировых стандартов качества. Может у кого-то его навалом, или ему за это платят, кодят же boost люди, но у меня на это нет мотивации. Во-вторых, где я найду время оформить по правилам гитхаба? Ты видишь, сколько времени я угробил на эти темы, а ведь тут оформления почитай-то и нет.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776571</guid>
        <pubDate>Mon, 20 Aug 2018 16:36:07 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776571</link>
        <description><![CDATA[Flex Ferrum: А чего бы тебе всё это на гитхаб не выложить?]]></description>
        <author>Flex Ferrum</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776570</guid>
        <pubDate>Mon, 20 Aug 2018 16:30:06 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776570</link>
        <description><![CDATA[Qraizer: Что-то халявлю, надо навёрстывать.<br>
Итак, реализация. Списки типов и кортежы те же самые. Ну, мне по-прежнему несложно скопипастить, чтоб по разным темам не гонять.<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">/*****************************************************************\</div><div class="code_line">** Списки типов. Несмотря на наличие variadic templates в C++1x, **</div><div class="code_line">** &nbsp; &nbsp; которые решают множество проблем в обобщённом коде, &nbsp; &nbsp; &nbsp; **</div><div class="code_line">** &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; для метакода списки всё равно удобнее. &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;**</div><div class="code_line">\*****************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">#ifndef TLIST_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div><div class="code_line">#define TLIST_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div><div class="code_line">&nbsp;</div><div class="code_line">#include &#60;type_traits&#62;</div><div class="code_line">&nbsp;</div><div class="code_line">namespace Types_Lists</div><div class="code_line">{</div><div class="code_line">&nbsp;</div><div class="code_line">/* Терминальный тип */</div><div class="code_line">struct NullType {};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Список типов.</div><div class="code_line">&nbsp;&nbsp; L - голова, любой тип, кроме терминального и списка.</div><div class="code_line">&nbsp;&nbsp; R - хвост, либо терминальный тип, либо список */</div><div class="code_line">template &#60;typename L, typename R&#62; struct TList</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef L Head;</div><div class="code_line">&nbsp;&nbsp;typedef R Tail;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Создание списка через вариадики. */</div><div class="code_line">template &#60;typename L, typename ...R&#62; struct MakeTypeList</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;L, typename MakeTypeList&#60;R...&#62;::type&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename T&#62; struct MakeTypeList&#60;T&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;T, NullType&#62; type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">template &#60;typename L, typename ...R&#62;</div><div class="code_line">using MakeTList = typename MakeTypeList&#60;L, R...&#62;::type;</div><div class="code_line">&nbsp;</div><div class="code_line">/* Генератор веерной иерархии на основе списка типов T.</div><div class="code_line">&nbsp;&nbsp; Все типы из списка T применяются к шаблону Node. Первый его параметр - параметризированный</div><div class="code_line">&nbsp;&nbsp; тип Head из списка, второй - тип возвращаемого значения мультиметода.</div><div class="code_line">&nbsp;&nbsp; Все получившиеся Node&#60;T::Head&#62; не состоят в родстве относительно друг друга, что</div><div class="code_line">&nbsp;&nbsp; обеспечивает их равноправность при перекрытии. Получившая веерная иерархия будет т.о.</div><div class="code_line">&nbsp;&nbsp; содержать в каждом луче веера декларацию интерфейса абстрактного акцептора для отдельного</div><div class="code_line">&nbsp;&nbsp; типа из списка. От базы (самого производного класса GenHierarchy&#60;&#62;) можно однозначно добраться</div><div class="code_line">&nbsp;&nbsp; до любого узла путём обычного восходящего приведения типов. */</div><div class="code_line">template &#60;template &#60;typename, typename&#62; class Node, typename Ret, typename T&#62; struct GenHierarchy;</div><div class="code_line">template &#60;template &#60;typename, typename&#62; class Node, typename Ret, typename L, typename R&#62;</div><div class="code_line">struct GenHierarchy&#60;Node, Ret, TList&#60;L, R&#62; &#62;: public Node&#60;L, Ret&#62;, public GenHierarchy&#60;Node, Ret, R&#62;</div><div class="code_line">{</div><div class="code_line">};</div><div class="code_line">template &#60;template &#60;typename, typename&#62; class Node, typename Ret&#62;</div><div class="code_line">struct GenHierarchy&#60;Node, Ret, NullType&#62;</div><div class="code_line">{</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Метафункция получения самого базового класса из списка типов */</div><div class="code_line">template &#60;typename TL&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct MostBase;</div><div class="code_line">template &#60;typename L, typename R&#62; struct MostBase&#60;TList&#60;L, R&#62; &#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;R&#62;::type &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nextType;</div><div class="code_line">&nbsp;&nbsp;typedef typename std::conditional&#60;std::is_base_of_v&#60;L, nextType&#62;, L, nextType&#62;::type type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename T&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct MostBase&#60;TList&#60;T, NullType&#62; &#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef T type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Метафункция получения длины списка */</div><div class="code_line">template &#60;typename TL&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct Length;</div><div class="code_line">template &#60;typename L, typename R&#62; struct Length&#60;TList&#60;L, R&#62; &#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;enum { value = Length&#60;R&#62;::value + 1 };</div><div class="code_line">};</div><div class="code_line">template &#60;&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct Length&#60;NullType&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;enum { value = 0 };</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Метафункция получения типа из списка по его номеру */</div><div class="code_line">template &#60;typename TL, int I&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct GetType;</div><div class="code_line">template &#60;typename L, typename R, int I&#62; struct GetType&#60;TList&#60;L, R&#62;, I&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename GetType&#60;R, I-1&#62;::type type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; &nbsp; &nbsp; &nbsp; &nbsp;struct GetType&#60;TList&#60;L, R&#62;, 0&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef L type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">} // Types_Lists</div><div class="code_line">&nbsp;</div><div class="code_line">#endif // TLIST_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div></ol></div></div></div></div><div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">/****************************************************************\</div><div class="code_line">** &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Кортежи. &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;**</div><div class="code_line">** Стандартные из std по ряду причин без адаптеров не подходят. **</div><div class="code_line">\****************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">#ifndef TUPLE_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div><div class="code_line">#define TUPLE_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div><div class="code_line">&nbsp;</div><div class="code_line">#include &quot;tlist.h&quot;</div><div class="code_line">&nbsp;</div><div class="code_line">namespace Tuples</div><div class="code_line">{</div><div class="code_line">&nbsp;</div><div class="code_line">using Types_Lists::TList;</div><div class="code_line">using Types_Lists::NullType;</div><div class="code_line">&nbsp;</div><div class="code_line">/* Узел кортежа, одно поле. Первый параметр требуется для уникальной его идентификации,</div><div class="code_line">&nbsp;&nbsp; если в пределах кортежа T неуникален. */</div><div class="code_line">template &#60;typename Hash, typename T&#62; struct Field</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;T&amp;&amp; data;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;Field(T&amp;&amp; t) : data(std::forward&#60;T&#62;(t)) {}</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Генератор кортежа на основе списка типов T.</div><div class="code_line">&nbsp;&nbsp; В качестве Hash используется текущий срез списка типов. */</div><div class="code_line">template &#60;typename T&#62; struct Tuple;</div><div class="code_line">template &#60;typename L, typename R&#62;</div><div class="code_line">struct Tuple&#60;TList&#60;L, R&#62; &#62;: public Field&#60;TList&#60;L, R&#62;, L&#62;, public Tuple&#60;R&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;L, R&#62; TypeList;</div><div class="code_line">&nbsp;&nbsp;typedef L &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DataType;</div><div class="code_line">&nbsp;&nbsp;typedef Tuple&#60;R&#62; &nbsp; &nbsp;base_type;</div><div class="code_line">&nbsp;&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Конструкторы нужны, чтобы позволить полям иметь константные и ссылочные типы. */</div><div class="code_line">&nbsp;&nbsp;Tuple(L&amp;&amp; l): &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Field&#60;TList&#60;L, R&#62;, L&#62;(std::forward&#60;L&#62;(l)) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;template &#60;typename ...Args&#62;</div><div class="code_line">&nbsp;&nbsp;Tuple(L&amp;&amp; l, Args&amp;&amp;... args): Field&#60;TList&#60;L, R&#62;, L&#62;(std::forward&#60;L&#62;(l)),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;base_type(std::forward&#60;Args&#62;(args)...) &nbsp; &nbsp;{}</div><div class="code_line">};</div><div class="code_line">template &#60;&#62;</div><div class="code_line">struct Tuple&#60;NullType&#62;</div><div class="code_line">{</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Внутренности реализации. */</div><div class="code_line">namespace details</div><div class="code_line">{</div><div class="code_line">&nbsp;</div><div class="code_line">/* Получить срез кортежа Tpl по номеру поля I от начала */</div><div class="code_line">template &#60;int I, typename Tpl&#62; struct GetTupleSlice</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename GetTupleSlice&#60;I-1, typename Tpl::base_type&#62;::type type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename Tpl&#62; &nbsp; &nbsp; &nbsp; &nbsp;struct GetTupleSlice&#60;0, Tpl&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef Tpl type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">} // details</div><div class="code_line">&nbsp;</div><div class="code_line">/* Получить поле I кортежа Tpl */</div><div class="code_line">template &#60;int I, typename Tpl&#62;</div><div class="code_line">typename details::GetTupleSlice&#60;I, Tpl&#62;::type::DataType&amp;&amp; GetField(Tpl&amp; tuple)</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename details::GetTupleSlice&#60;I, Tpl&#62;::type TupleSlice;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;return std::forward&#60;typename TupleSlice::DataType&#62;(</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;static_cast&#60;Field&#60;typename TupleSlice::TypeList,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TupleSlice::DataType&#62;&amp;&#62;(tuple).data);</div><div class="code_line">}</div><div class="code_line">&nbsp;</div><div class="code_line">} // Tuples</div><div class="code_line">&nbsp;</div><div class="code_line">#endif // TUPLE_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div></ol></div></div></div></div>А вот мультиметоды, конечно, другие.<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">#ifndef MULTIMETHODS_H_0A0E1659_FD72_4B5B_A091_EF59C8050584</div><div class="code_line">#define MULTIMETHODS_H_0A0E1659_FD72_4B5B_A091_EF59C8050584</div><div class="code_line">&nbsp;</div><div class="code_line">#include &quot;tlist.h&quot;</div><div class="code_line">#include &quot;tuple.h&quot;</div><div class="code_line">&nbsp;</div><div class="code_line">namespace MultiMethods</div><div class="code_line">{</div><div class="code_line">&nbsp;</div><div class="code_line">/* Фактически списки типов и кортежи разрабатывались для мультиметодов, и их использование</div><div class="code_line">&nbsp;&nbsp; без них вряд ли имеет смысл. Если нужны, лучше заюзать стандартные из буста или C++1x.</div><div class="code_line">&nbsp;&nbsp; Так как мультиметоды очень плотно связаны как с теми, так и с другими, нет смысла скрывать эту</div><div class="code_line">&nbsp;&nbsp; связь. */</div><div class="code_line">using namespace Types_Lists;</div><div class="code_line">using namespace Tuples;</div><div class="code_line">&nbsp;</div><div class="code_line">/* Внутренности реализации (приватный интерфейс). */</div><div class="code_line">namespace details</div><div class="code_line">{</div><div class="code_line">&nbsp;</div><div class="code_line">/* Узел веерной иерархии абстрактного акцептора. Документирует интерфейс Visitor-а */</div><div class="code_line">template &#60;typename T, typename Ret&#62; class Acceptor</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;virtual Ret Accept(T*&amp;&amp; obj) = 0;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Строит список типов параметров &quot;базового&quot; мультиметода на основе</div><div class="code_line">&nbsp;&nbsp; акцепторов абстрактного диспетчера и типов параметров, с которыми вызван его operator().</div><div class="code_line">&nbsp;&nbsp; Заменяет списки типов, описывающих иерархии динамически связываемых аргументов, на самые</div><div class="code_line">&nbsp;&nbsp; базовые классы в этих иерархиях. Применяя эту же операция для статически связваемых</div><div class="code_line">&nbsp;&nbsp; аргументов, фактически ничего не меняет, т.к. там всего один тип в списке.*/</div><div class="code_line">template &#60;typename&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct MakeParamTypes;</div><div class="code_line">template &#60;typename Tl, typename Tr&#62; struct MakeParamTypes&#60;TList&#60;Tl, Tr&#62;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;typename Tl::template ParamType&#60;typename MostBase&#60;typename Tl::TypeList&#62;::type&#62;::type,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename MakeParamTypes&#60;Tr&#62;::type&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct MakeParamTypes&#60;NullType&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef NullType type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/********************************************************************************\</div><div class="code_line">*************** &nbsp; &nbsp; &nbsp;Абстрактные акцепторы. Всего их две штуки. &nbsp; &nbsp; **************</div><div class="code_line">\********************************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">/* Динамический акцептор. Обрабатывает динамически связываемые параметры.</div><div class="code_line">&nbsp;&nbsp; Первый параметр - список типов, должен включать базовый и все производные от него классы,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; которые предполагается передавать аргументом в мультиметод,</div><div class="code_line">&nbsp;&nbsp; второй &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- тип возвращаемого значения мультиметода. */</div><div class="code_line">template &#60;typename TL, typename Ret&#62; class LinkDynamic: public GenHierarchy&#60;details::Acceptor, Ret, TL&#62;</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;typedef TL TypeList;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// вызывается конкретным акцептором, восстановливает динамический тип t</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename X&#62;</div><div class="code_line">&nbsp;&nbsp;Ret apply(T* t, X&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;return t-&#62;Accept(*this); &nbsp; // делегировать восстановление типа самому t</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Генератор конкретных акцепторов, реализующих чистые методы абстрактных акцепторов.</div><div class="code_line">&nbsp;&nbsp; &nbsp; Всего их два разных. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;template &#60;typename, typename, typename, typename, typename, typename&#62; class GA,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename ATL, typename CTL, typename TPL, typename SRC&#62;</div><div class="code_line">&nbsp;&nbsp;struct MakeAcceptor</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef GA&#60;T, TL, ATL, CTL, TPL, SRC&#62; type;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Используется details::MakeParamTypes&#60;&#62; для получения типа параметра мультиметода.</div><div class="code_line">&nbsp;&nbsp; &nbsp; Для динамического акцептора это указатель на тип Head из TL. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62; struct ParamType { typedef T* type; };</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Статическый акцептор. Обрабатывает статически связываемые параметры.</div><div class="code_line">&nbsp;&nbsp; Первый параметр - непосредственно тип аргумента мультиметода,</div><div class="code_line">&nbsp;&nbsp; второй &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- тип возвращаемого значения мультиметода. */</div><div class="code_line">template &#60;typename Type, typename Ret&#62; class LinkStatic</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;Type, NullType&#62; TypeList;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// вызывается конкретным акцептором; восстанавливать нечего, просто вызывает следующий акцептор</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename X&#62;</div><div class="code_line">&nbsp;&nbsp;Ret apply(T&amp;&amp; t, X&amp; acceptor)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;return acceptor.Accept(std::forward&#60;T&#62;(t));</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Такой же генератор конкретных акцепторов. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;template &#60;typename, typename, typename, typename, typename, typename&#62; class GA,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename ATL, typename CTL, typename TPL, typename SRC&#62;</div><div class="code_line">&nbsp;&nbsp;struct MakeAcceptor</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef GA&#60;T, TypeList, ATL, CTL, TPL, SRC&#62; type;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Используется details::MakeParamTypes&#60;&#62; для получения типа параметра мультиметода.</div><div class="code_line">&nbsp;&nbsp; &nbsp; Для статического акцептора это rvalue ссылка на тип Type. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62; struct ParamType { typedef T&amp;&amp; type; };</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/********************************************************************************\</div><div class="code_line">************* &nbsp; &nbsp; &nbsp; &nbsp;Стратегии работы с параметрами диспетчера. &nbsp; &nbsp; &nbsp; ************</div><div class="code_line">******* &nbsp; &nbsp; &nbsp; Увы, &#60;type_traits&#62; не поможет: там типы, а тут шаблоны &nbsp; &nbsp; &nbsp; *******</div><div class="code_line">\********************************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">/* Преобразование типа аргумента диспетчера в тип его параметра. */</div><div class="code_line">&nbsp;</div><div class="code_line">// Статически связываемые параметры. Типы совпадают.</div><div class="code_line">template &#60;typename T&#62; struct MakeArg</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef T type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">// Динамически связываемые параметры.</div><div class="code_line">// Список типов пребразуется в cv-неквалифицированный тип указателя на самый базовый класс.</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;TList&#60;L, R&#62;&#62;; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// намерено не реализован</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;TList&#60;L, R&#62;*&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// *</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;const TList&#60;L, R&#62;*&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// const *</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;const volatile TList&#60;L, R&#62;*&#62; &nbsp; // const volatile *</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;volatile TList&#60;L, R&#62;*&#62; &nbsp; &nbsp; &nbsp; &nbsp; // volatile *</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;TList&#60;L, R&#62;&amp;&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// &amp;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;const TList&#60;L, R&#62;&amp;&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// const &amp;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;const volatile TList&#60;L, R&#62;&amp;&#62; &nbsp; // const volatile &amp;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;volatile TList&#60;L, R&#62;&amp;&#62; &nbsp; &nbsp; &nbsp; &nbsp; // volatile &amp;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct MakeArg&#60;TList&#60;L, R&#62;&amp;&amp;&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // &amp;&amp;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef typename MostBase&#60;TList&#60;L, R&#62;&#62;::type *type;</div><div class="code_line">};</div><div class="code_line">// Технически тут могут быть cv-квалифицированные варианты для &amp;&amp;, но кому они нужны</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;</div><div class="code_line">/* Выбор политики для обработки диспетчером его параметров */</div><div class="code_line">&nbsp;</div><div class="code_line">// Статически связываемые параметры. Политика статического связывания.</div><div class="code_line">template &#60;typename T, typename RT&#62; struct MakeParam</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkStatic&#60;T, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">// Динамически связываемые параметры. Политика динамического связывания.</div><div class="code_line">// Все варианты как и у MakeArg&#60;&#62;.</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;TList&#60;L, R&#62;, RT&#62;;</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;TList&#60;L, R&#62;*, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;const TList&#60;L, R&#62;*, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;const volatile TList&#60;L, R&#62;*, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;volatile TList&#60;L, R&#62;*, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;TList&#60;L, R&#62;&amp;, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;const TList&#60;L, R&#62;&amp;, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;const volatile TList&#60;L, R&#62;&amp;, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;volatile TList&#60;L, R&#62;&amp;, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R, typename RT&#62; struct MakeParam&#60;TList&#60;L, R&#62;&amp;&amp;, RT&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef details::LinkDynamic&#60;TList&#60;L, R&#62;, RT&#62; type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Построить список типов политик для всех параметров диспетчера.</div><div class="code_line">&nbsp;&nbsp; RT - return type, перенесён в начало списка параметров для бесконфликности с вариадиком. */</div><div class="code_line">template &#60;typename RT, typename T, typename ...List&#62; struct MakeParams</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;typename MakeParam&#60;T, RT&#62;::type, typename MakeParams&#60;RT, List...&#62;::type&#62; type;</div><div class="code_line">};</div><div class="code_line">template &#60;typename RT, typename T&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct MakeParams&#60;RT, T&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;typedef TList&#60;typename MakeParam&#60;T, RT&#62;::type, NullType&#62; type;</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Предобработка параметра, переданного диспетчеру.</div><div class="code_line">&nbsp;&nbsp; Нужна частичная специализация, т.к. работа основана на вариадике диспетчера, куда замешаны</div><div class="code_line">&nbsp;&nbsp; списки типов вместо фактических типов. А чтобы не заморачиваться MostBase&#60;&#62;, внутри нужен и</div><div class="code_line">&nbsp;&nbsp; простой шаблонный метод для обработки собственно параметра. */</div><div class="code_line">&nbsp;</div><div class="code_line">// Статически связываемый параметр. Просто форвард.</div><div class="code_line">template &#60;typename A&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct mkref</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T&amp;&amp; doIt(T&amp;&amp; t) { return std::forward&#60;T&#62;(t); }</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">// Динамически связываемый параметр. Нужно убрать cv-квалификаторы и преобразовать в указатель.</div><div class="code_line">// Все варианты как и у MakeArg&#60;&#62;.</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;TList&#60;L, R&#62;&#62;;</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return t; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;const TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(const T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return const_cast&#60;T*&#62;(t); &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;const volatile TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(const volatile T* t) { return const_cast&#60;T*&#62;(t); &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;volatile TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(volatile T* t) &nbsp; &nbsp; &nbsp; { return const_cast&#60;T*&#62;(t); &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(T&amp; t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return &t; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;const TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(const T&amp; t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return &amp;const_cast&#60;T&amp;&#62;(t); }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;const volatile TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(const volatile T&amp; t) { return &amp;const_cast&#60;T&amp;&#62;(t); }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;volatile TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(volatile T&amp; t) &nbsp; &nbsp; &nbsp; { return &amp;const_cast&#60;T&amp;&#62;(t); }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct mkref&#60;TList&#60;L, R&#62;&amp;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T* doIt(T&amp;&amp; t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { return &t; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Постобработка параметра, переданного диспетчеру.</div><div class="code_line">&nbsp;&nbsp; Нужна частичная специализация, т.к. работа основана на вариадике диспетчера, куда замешаны</div><div class="code_line">&nbsp;&nbsp; списки типов вместо фактических типов + там же лежат исходные cv- и ptr/rev квалификаторы.</div><div class="code_line">&nbsp;&nbsp; А чтобы не заморачиваться MostBase&#60;&#62;, внутри нужен и простой шаблонный метод для обработки</div><div class="code_line">&nbsp;&nbsp; собственно параметра. */</div><div class="code_line">&nbsp;</div><div class="code_line">// Статически связываемый параметр. Всё могло быть проще, мог быть просто форвард. Но реальность</div><div class="code_line">// такова, что для просто форварда нет разницы между rvalue и rvalue ref, в результате объекты,</div><div class="code_line">// принимаемые мультиметодом по значению, переносятся вместо того, чтобы копироваться.</div><div class="code_line">template &#60;typename X&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct dcref</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doIt(T&amp;&amp; t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { return t; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename X&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct dcref&#60;X&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T&amp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;doIt(T&amp; t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return t; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename X&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct dcref&#60;const X&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const T&amp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;doIt(const T&amp; t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return t; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename X&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct dcref&#60;const volatile X&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const volatile T&amp; doIt(const volatile T&amp; t) { return t; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename X&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct dcref&#60;volatile X&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static volatile T&amp; &nbsp; &nbsp; &nbsp; doIt(volatile T&amp; t) &nbsp; &nbsp; &nbsp; { return t; }</div><div class="code_line">};</div><div class="code_line">// вот ради этого весь сыр-бор</div><div class="code_line">template &#60;typename X&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct dcref&#60;X&amp;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T&amp;&amp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; doIt(T&amp;&amp; t){return std::forward&#60;T&#62;(t);}</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">// Динамически связываемый параметр. Нужно вернуть исходные его cv- и ptr/ref квалификаторы.</div><div class="code_line">// Все варианты как и у MakeArg&#60;&#62;.</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;TList&#60;L, R&#62;&#62;;</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static &nbsp; &nbsp; &nbsp; T* doIt(T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return t; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;const TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const T* doIt(T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return const_cast&#60;const T*&#62;(t); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;const volatile TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const volatile T* doIt(T* t) { return const_cast&#60;const volatile T*&#62;(t); &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;volatile TList&#60;L, R&#62;*&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static volatile T* doIt(T* t) &nbsp; &nbsp; &nbsp; { return const_cast&#60;volatile T*&#62;(t); &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static &nbsp; &nbsp; &nbsp; T&amp; doIt(T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return *t; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;const TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const T&amp; doIt(T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return const_cast&#60;const T&amp;&#62;(*t); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;const volatile TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const volatile T&amp; doIt(T* t) { return const_cast&#60;const volatile T&amp;&#62;(*t); }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;volatile TList&#60;L, R&#62;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static volatile T&amp; doIt(T* t) &nbsp; &nbsp; &nbsp; { return const_cast&#60;volatile T&amp;&#62;(*t); &nbsp; &nbsp; &nbsp; }</div><div class="code_line">};</div><div class="code_line">template &#60;typename L, typename R&#62; struct dcref&#60;TList&#60;L, R&#62;&amp;&amp;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static T&amp;&amp; doIt(T* t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { return std::move(*t); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">} // details</div><div class="code_line">&nbsp;</div><div class="code_line">/********************************************************************************\</div><div class="code_line">***************** &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Абстрактный диспетчер &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;****************</div><div class="code_line">\********************************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">/* Конкретный диспетчер */</div><div class="code_line">template &#60;typename, typename, typename ...&#62; class CallConcrete;</div><div class="code_line">&nbsp;</div><div class="code_line">/* Прототип диспетчера. Должен быть отделён от диспетчера, иначе получается циклическая связь между</div><div class="code_line">&nbsp;&nbsp; определениями абстрактных акцепторов и объявлениями visit-методов в классах пользователя.</div><div class="code_line">&nbsp;&nbsp; Первый параметр - пользовательский класс с реализациями перекрытых мультиметодов,</div><div class="code_line">&nbsp;&nbsp; второй &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- тип возвращаемого мультиметодом значения,</div><div class="code_line">&nbsp;&nbsp; третий... &nbsp; &nbsp; &nbsp; - типы параметров. */</div><div class="code_line">template &#60;typename DI, typename RetType, typename ...Args&#62;</div><div class="code_line">struct Prototype</div><div class="code_line">{</div><div class="code_line">protected:</div><div class="code_line">&nbsp;&nbsp;// преобразовать типы параметров мультиметода в аргументы</div><div class="code_line">&nbsp;&nbsp;// фактически это список абстрактных акцепторов</div><div class="code_line">&nbsp;&nbsp;typedef typename details::MakeParams&#60;RetType, Args...&#62;::type TTl;</div><div class="code_line">&nbsp;</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;typedef RetType ret_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Получить тип абстрактного акцептора по списку типов иерархии.</div><div class="code_line">&nbsp;&nbsp; &nbsp; Требуется в visit-методах пользовательских классов, чтобы от него выбрать свой интерфейс.</div><div class="code_line">&nbsp;&nbsp; &nbsp; В версии для C++03 абстрактные акцепторы создавались пользователем, тут их создаёт сам диспетчер,</div><div class="code_line">&nbsp;&nbsp; &nbsp; так что пользовать диспетчер стало проще, а реализовать visit-метод сложнее. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename TL&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct getArg;</div><div class="code_line">&nbsp;&nbsp;template &#60;typename H, typename T&#62; struct getArg&#60;TList&#60;H, T&#62;&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;// Найти список типов иерархии в аргументах мультиметода</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename X, typename Y, typename Tl&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct findType;</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename X, typename Y, typename L, typename R&#62; struct findType&#60;X, Y, TList&#60;L, R&#62;&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typedef typename findType&#60;X, typename R::Head::TypeList, R&#62;::type type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;};</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename X, typename L, typename R&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct findType&#60;X, X, TList&#60;L, R&#62;&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typedef L type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;};</div><div class="code_line">&nbsp;&nbsp; &nbsp;// Найти LinkDynamic&#60;&#62; запрошенного TList&#60;&#62; в TTl</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename findType&#60;TList&#60;H, T&#62;, typename TTl::Head::TypeList, TTl&#62;::type type;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">};</div><div class="code_line">// Специализация для беспараметрических мультиметодов</div><div class="code_line">template &#60;typename DI, typename RetType&#62; struct Prototype&#60;DI, RetType&#62; {};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Абстрактный диспетчер. Принимает свой прототип. */</div><div class="code_line">template &#60;typename Proto&#62; class Dispatcher;</div><div class="code_line">&nbsp;</div><div class="code_line">template &#60;typename DI, typename RetType, typename ...Args&#62; </div><div class="code_line">class Dispatcher&#60;Prototype&#60;DI, RetType, Args...&#62;&#62;: Prototype&#60;DI, RetType, Args...&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;using typename Prototype&#60;DI, RetType, Args...&#62;::TTl;</div><div class="code_line">&nbsp;</div><div class="code_line">/********************************************************************************\</div><div class="code_line">*************** &nbsp; &nbsp; &nbsp; Конкретные акцепторы. Всего их две штуки &nbsp; &nbsp; &nbsp;**************</div><div class="code_line">\********************************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Конкретные акцепторы. IterAcceptorCaller обрабатывает все параметры, кроме последнего,</div><div class="code_line">&nbsp;&nbsp; &nbsp; LastAcceptorCaller обрабатывает последний параметр. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename CTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename PTL, typename TPL, typename SRC&#62; struct IterAcceptorCaller;</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename CTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename PTL, typename TPL, typename SRC&#62; struct LastAcceptorCaller;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Генератор очередного конкретного акцептора на основе очередного среза списка типов</div><div class="code_line">&nbsp;&nbsp; &nbsp; абстрактных акцепторов. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename PTL, typename TPL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename SRC&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct AcceptorMaker;</div><div class="code_line">&nbsp;&nbsp;// эта специализация является очередной итерацией цикла и генерирует очередной акцептор</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename AL, &nbsp;typename AR, typename PTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TPL, typename SRC&#62; struct AcceptorMaker&#60;T, TList&#60;AL, AR&#62;, PTL, TPL, SRC&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename AL::template MakeAcceptor&#60;T, IterAcceptorCaller,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TList&#60;AL, AR&#62;, &nbsp; &nbsp; &nbsp; PTL, TPL, SRC&#62;::type type;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;&nbsp;// эта специализация является последней итерацией цикла</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename AL, &nbsp;typename PTL, typename TPL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename SRC&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct AcceptorMaker&#60;T, TList&#60;AL, NullType&#62;, PTL, TPL, SRC&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename AL::template MakeAcceptor&#60;T, LastAcceptorCaller,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;TList&#60;AL, NullType&#62;, PTL, TPL, SRC&#62;::type type;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Реализация конкретных акцепторов. Общий принцип заключается в генерации линейной иерархии</div><div class="code_line">&nbsp;&nbsp; &nbsp; на основе абстрактного акцептора. Очередной узел в иерархии является производным от предыдущего</div><div class="code_line">&nbsp;&nbsp; &nbsp; узла и реализует интерфейс очередного Visitor-а из веерной иерархии. В совокупности вся линейная</div><div class="code_line">&nbsp;&nbsp; &nbsp; иерархия конкретного акцептора реализует все интерфейсы этого Visitor-а. Последний узел</div><div class="code_line">&nbsp;&nbsp; &nbsp; производится непосредственно от абстрактного акцептора, который эти интерфейсы документировал.</div><div class="code_line">&nbsp;&nbsp; &nbsp; В целом, т.к. и конкретный, и абстрактный акцепторы строятся на основе одинаковых списков типов,</div><div class="code_line">&nbsp;&nbsp; &nbsp; реализованным оказывается каждый узел из веерной иерархии, и каждый - в своём узле линейной</div><div class="code_line">&nbsp;&nbsp; &nbsp; иерархии. В результате позднее связываение метода Accept() вызовет нужный узел, которому</div><div class="code_line">&nbsp;&nbsp; &nbsp; известен его тип в списке, тем самым динамический тип восстанавливается, и тип параметра может</div><div class="code_line">&nbsp;&nbsp; &nbsp; быть приведён к восстановленному без dynamic_cast&#60;&#62;. Восстановленные типы накапливаются в</div><div class="code_line">&nbsp;&nbsp; &nbsp; списке восстановленных типов. В заключение вызывается следующий конкретный акцептор.</div><div class="code_line">&nbsp;&nbsp; &nbsp; Параметры:</div><div class="code_line">&nbsp;&nbsp; &nbsp; - тип возвращаемого значения;</div><div class="code_line">&nbsp;&nbsp; &nbsp; - срез списка типов иерархии своего параметра;</div><div class="code_line">&nbsp;&nbsp; &nbsp; - срез списка типов параметров диспетчера (точнее, его прототипа);</div><div class="code_line">&nbsp;&nbsp; &nbsp; - список восстановленных динамических типов предыдущих параметров (в обратном порядке);</div><div class="code_line">&nbsp;&nbsp; &nbsp; - срез списка типов параметров мультиметода;</div><div class="code_line">&nbsp;&nbsp; &nbsp; - тип исходного кортежа с параметрами doIt(). */</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Реализация конкретного акцептора последнего параметра мультиметода. Особенности:</div><div class="code_line">&nbsp;&nbsp; &nbsp; - срез списка типов параметров мультиметода не используется, ибо тут он уже пуст.</div><div class="code_line">&nbsp;&nbsp; &nbsp; - вызывает конкретный диспетчер вместо следующего конкретного акцептора. */</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// это все апцепторы в иерархии, кроме самого базового</div><div class="code_line">&nbsp;&nbsp;template &#60;typename L, typename R, typename CTL, typename PTL, typename TPL, typename SRC&#62;</div><div class="code_line">&nbsp;&nbsp;struct LastAcceptorCaller&#60;RetType, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC&#62;:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public LastAcceptorCaller&#60;RetType, R, CTL, PTL, TPL, SRC&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef LastAcceptorCaller&#60;RetType, R, &nbsp;CTL, PTL, TPL, SRC&#62; base_type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;L&#62;::type &nbsp; &nbsp; arg_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;LastAcceptorCaller(SRC&amp; ptl, TPL&amp; src): base_type(ptl, src) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// Восстанавливает тип последнего параметра и вызывает нужную специализацию конкретного</div><div class="code_line">&nbsp;&nbsp; &nbsp;// диспетчера для преобразования кортежа обратно в вариадик; последний параметр нет смысла</div><div class="code_line">&nbsp;&nbsp; &nbsp;// включать в кортеж, т.к. это потребует также модификации списков типов, потому</div><div class="code_line">&nbsp;&nbsp; &nbsp;// его проще передать явно вместе с его восстановленным типом.</div><div class="code_line">&nbsp;&nbsp; &nbsp;RetType Accept(arg_type&amp;&amp; obj)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return CallConcrete&#60;DI, RetType, Args...&#62;::template apply&#60;SRC, PTL, arg_type&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;::call(base_type::m_Params, std::forward&#60;arg_type&#62;(obj));</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;&nbsp;// это базовый в иерархии акцептор; весь список типов иерархии параметра уже обработан производными</div><div class="code_line">&nbsp;&nbsp;// классами, так что этот с ними уже не работает, он только хранит общую для них информацию и</div><div class="code_line">&nbsp;&nbsp;// наследует интерфейсы Visitor-а от абстрактного акцептора</div><div class="code_line">&nbsp;&nbsp;template &#60;typename CTL, typename PTL, typename TPL, typename SRC&#62;</div><div class="code_line">&nbsp;&nbsp;struct LastAcceptorCaller&#60;RetType, NullType, CTL, PTL, TPL, SRC&#62; : public CTL::Head</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;LastAcceptorCaller(SRC&amp; ptl, TPL&amp;): m_Params(ptl) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;SRC &m_Params;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Реализация конкретного акцептора всех параметров мультиметода, кроме последнего. Особенности:</div><div class="code_line">&nbsp;&nbsp; &nbsp; - используется, если мультиметод имеет более 1 параметра. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename L, typename R, typename CTL, typename PTL, typename TPL, typename SRC&#62;</div><div class="code_line">&nbsp;&nbsp;struct IterAcceptorCaller&#60;RetType, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC&#62; :</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public IterAcceptorCaller&#60;RetType, R, CTL, PTL, TPL, SRC&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef IterAcceptorCaller&#60;RetType, R, &nbsp;CTL, PTL, TPL, SRC&#62; base_type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;L&#62;::type &nbsp; &nbsp; arg_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;IterAcceptorCaller(SRC&amp; ptl, TPL&amp; src): base_type(ptl, src) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;/* восстановление типа очередного параметра, генерация следующего конкретного акцептора,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; передача ему следующего среза списка абстрактных акцепторов, базовых типов параметров</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; мультиметода и накопленной восстановленной информации о динамических типах и его вызов. */</div><div class="code_line">&nbsp;&nbsp; &nbsp;// выглядит странным, но да, сам параметр метода не нужен, важен лишь его тип для того, чтобы</div><div class="code_line">&nbsp;&nbsp; &nbsp;// динамический тип был правильно восстановлен; (точнее, даже он нужен лишь самому последнему</div><div class="code_line">&nbsp;&nbsp; &nbsp;// акцептору, а тип нужен лишь для помещения в список восстановленных типов); сами параметры</div><div class="code_line">&nbsp;&nbsp; &nbsp;// всё равно лежат в кортеже, им нужен только лишь static_cast&#60;&#62;, который позже сделает</div><div class="code_line">&nbsp;&nbsp; &nbsp;// конкретный диспетчер</div><div class="code_line">&nbsp;&nbsp; &nbsp;RetType Accept(arg_type&amp;&amp;)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typedef decltype(GetField&#60;0&#62;(base_type::m_Args)) realType;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typedef typename AcceptorMaker&#60;RetType, typename CTL::Tail, TList&#60;arg_type, PTL&#62;,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TPL::base_type, SRC&#62;::type acceptor;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;acceptor a(base_type::m_Params, static_cast&#60;typename TPL::base_type&amp;&#62;(base_type::m_Args));</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return a.apply(std::forward&#60;realType&#62;(GetField&#60;0&#62;(base_type::m_Args)), a);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;&nbsp;// это базовый в иерархии акцептор; весь список типов иерархии параметра уже обработан производными</div><div class="code_line">&nbsp;&nbsp;// классами, так что этот с ними уже не работает, он только хранит общую для них информацию и</div><div class="code_line">&nbsp;&nbsp;// наследует интерфейсы Visitor-а от абстрактного акцептора</div><div class="code_line">&nbsp;&nbsp;template &#60;typename CTL, typename PTL, typename TPL, typename SRC&#62;</div><div class="code_line">&nbsp;&nbsp;struct IterAcceptorCaller&#60;RetType, NullType, CTL, PTL, TPL, SRC&#62; : public CTL::Head</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;IterAcceptorCaller(SRC&amp; ptl, TPL&amp; src): m_Params(ptl), m_Args(src) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;SRC &m_Params;</div><div class="code_line">&nbsp;&nbsp; &nbsp;TPL &m_Args;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Обобщённая точка входа. Создаёт акцептор первого параметра и вызывает его.</div><div class="code_line">&nbsp;&nbsp; &nbsp; См. комменты к IterAcceptorCaller::Accept(). */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename Tpl&#62;</div><div class="code_line">&nbsp;&nbsp;static RetType doIt(Tpl&amp; tpl)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef decltype(GetField&#60;0&#62;(tpl)) realType;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename Tpl::base_type TupleType;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename AcceptorMaker&#60;RetType, TTl, NullType, TupleType, Tpl&#62;::type acceptor;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;acceptor a(tpl, static_cast&#60;TupleType&amp;&#62;(tpl));</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return a.apply(std::forward&#60;realType&#62;(GetField&#60;0&#62;(tpl)), a);</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Промежуточный метод перед doIt().</div><div class="code_line">&nbsp;&nbsp; &nbsp; Выполняет вторую фазу обработки параметров: создание и заполнение кортежа. После этого этапа</div><div class="code_line">&nbsp;&nbsp; &nbsp; вариадиков больше нет, а все параметры прочеканы и предобработны. */</div><div class="code_line">&nbsp;&nbsp;RetType decay(typename details::MakeArg&#60;Args&#62;::type&amp;&amp;... args)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef Tuple&#60;typename details::MakeParamTypes&#60;TTl&#62;::type&#62; TupleType;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;TupleType tuple(std::forward&#60;typename details::MakeArg&#60;Args&#62;::type&#62;(args)...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;return doIt(tuple);</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;using typename Prototype&#60;DI, RetType, Args...&#62;::ret_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Точка вызова диспетчера. Аргументами могут прийти любые типы, т.к. они не обязаны строго</div><div class="code_line">&nbsp;&nbsp; &nbsp; совпадать с формальными параметрами мультиметода. Их соответствие проеряется по ходу дела,</div><div class="code_line">&nbsp;&nbsp; &nbsp; и ежели что, либо будет выполнен неявный каст, либо компилятор сообщит о проблеме.</div><div class="code_line">&nbsp;&nbsp; &nbsp; В отличие от реализации для C++03, тут возможно сохранить полную Стандартную семантику</div><div class="code_line">&nbsp;&nbsp; &nbsp; соответствия типов фактических параметров типам заявленных формальных. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp;ret_type operator ()(A&amp;&amp;... args)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;// Предобработка параметров, в ходе которой динамически связываемые сводятся к указателям на</div><div class="code_line">&nbsp;&nbsp; &nbsp;// cv-неквалифицированные значения, и выполняется проверка соответствия фатических параметров</div><div class="code_line">&nbsp;&nbsp; &nbsp;// формальным. Важно, чтобы static_cast&#60;&#62; выполнял каст к rvalue ref. Во-первых, это не даёт</div><div class="code_line">&nbsp;&nbsp; &nbsp;// ему выполнять явный каст типов там, где неявный бы провалился (например, каст explicit</div><div class="code_line">&nbsp;&nbsp; &nbsp;// конструктором), во-вторых, он сводит динамически связываемые параметры к их базовым классам,</div><div class="code_line">&nbsp;&nbsp; &nbsp;// что, вообще говоря, является его главным назначением.</div><div class="code_line">&nbsp;&nbsp; &nbsp;return decay(static_cast&#60;typename details::MakeArg&#60;Args&#62;::type&amp;&amp;&#62;(</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;details::mkref&#60;Args&#62;::doIt(std::forward&#60;A&#62;(args))) ...);</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Это тривиальный случай - у мультиметода параметры отсутствуют. */</div><div class="code_line">template &#60;typename DI, typename RetType&#62;</div><div class="code_line">struct Dispatcher&#60;Prototype&#60;DI, RetType&#62;&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;RetType operator ()()</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;return CallConcrete&#60;DI, RetType, NullType&#62;::template apply&#60;NullType, NullType, NullType&#62;::call();</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/*******************************************************************************\</div><div class="code_line">***************** &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Конкретный диспетчер &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;****************</div><div class="code_line">\*******************************************************************************/</div><div class="code_line">&nbsp;</div><div class="code_line">/* Первый параметр - пользовательский класс с реализациями перекрытых мультиметодов,</div><div class="code_line">&nbsp;&nbsp; второй &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- тип возвращаемого мультиметодом значения,</div><div class="code_line">&nbsp;&nbsp; третий &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;- исходный вариадик формальных параметров, по которому нужно будет выполнить</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; постобработку фактических. */</div><div class="code_line">template &#60;typename UI, typename Ret, typename ...Args&#62;</div><div class="code_line">struct CallConcrete</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;/* Преобразование кортежа обратно в вариадик с учётом восстановленных динамических типов.</div><div class="code_line">&nbsp;&nbsp; &nbsp; Обрабатывает все элементы кортежа, кроме последнего, который пришёл отдельно и уже обработан.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; SRC - исходный кортеж;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; PL &nbsp;- список восстановленных типов (в обратном порядке);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; Head- последний восстановленный тип.</div><div class="code_line">&nbsp;&nbsp; &nbsp; И тут тоже пригодились бы fold-expression из C++17. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename SRC, typename PL, typename Head&#62; struct apply</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;// обрабатывает очередной элемент кортежа</div><div class="code_line">&nbsp;&nbsp; &nbsp;// &nbsp; pl &nbsp; - исходный кортеж;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// &nbsp; data - последний параметр мультиметода; в касте не нуждается, т.к. передаётся вне контежа,</div><div class="code_line">&nbsp;&nbsp; &nbsp;// &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;и его тип уже целевой;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// &nbsp; args - уже обработанные параметры (при первом вызове пуст)</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;static Ret call(SRC&amp; pl, Head&amp;&amp; data, A&amp;&amp; ...args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// взять из кортежа очередной элемент (в обратном порядке), преобразовать к восстановленному</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// типу из PL и передать следующему преобразователю вместе с последним параметром и исходным</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// кортежем; так потихоньку наполняется вариадик</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return apply&#60;SRC, typename PL::Tail, Head&#62;::call(pl, std::forward&#60;Head&#62;(data),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;static_cast&#60;typename PL::Head&#62;(GetField&#60;Length&#60;PL&#62;::value-1&#62;(pl)),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;std::forward&#60;A&#62;(args)...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;&nbsp;/* Сюда попадаем, когда элементов кортежа больше нет (или и не было).</div><div class="code_line">&nbsp;&nbsp; &nbsp; Обрабатывает все элементы кортежа, кроме последнего.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; SRC - исходный кортеж;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; PL &nbsp;- список восстановленных типов (в обратном порядке);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; Head- последний восстановленный тип.</div><div class="code_line">&nbsp;&nbsp; &nbsp; И тут тоже пригодились бы fold-expression из C++17. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename SRC, typename Head&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct apply&#60;SRC, NullType, Head&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;// вызывается предыдущим apply&#60;&#62;::call(); все параметры восстановлены, осталось только</div><div class="code_line">&nbsp;&nbsp; &nbsp;// поставить на место последний параметр...</div><div class="code_line">&nbsp;&nbsp; &nbsp;// вообще говоря, эти два метода можно было бы объединить в один, если не то факт, что длины</div><div class="code_line">&nbsp;&nbsp; &nbsp;// вариадиков ...Args и ...A разные; поэтому сначала их sizeof... выравниваются</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;static Ret call(SRC&amp; pl, Head&amp;&amp; data, A&amp;&amp; ...args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return &nbsp; call(std::forward&#60;A&#62;(args)..., std::forward&#60;Head&#62;(data));</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;// ...выполнить постобработку каждого из них в соответствии с его политикой из ...Args</div><div class="code_line">&nbsp;&nbsp; &nbsp;// и вызвать пользовательский перекрытый мультиметод</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;static Ret call(A&amp;&amp; ...args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return UI::apply(details::dcref&#60;Args&#62;::doIt(std::forward&#60;A&#62;(args))...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;// отдельная специализация для беспараметрических мультиметодов</div><div class="code_line">&nbsp;&nbsp; &nbsp;static Ret call()</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return UI::apply();</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">} // MultiMethods</div><div class="code_line">&nbsp;</div><div class="code_line">/* Метод, который должен иметь любой полиморфный класс в иерархии, желающий участвовать в динамическом</div><div class="code_line">&nbsp;&nbsp; связывании. Реализован как макро для удобства.</div><div class="code_line">&nbsp;&nbsp; Первый параметр - прототип диспетчера; из него будет вытащен список параметров мультиметода;</div><div class="code_line">&nbsp;&nbsp; второй параметр - список типов иерархии, которой принадлежит полиморфный класс, он будет искаться</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; в списке параметров в прототипе;</div><div class="code_line">&nbsp;&nbsp; третий параметр - тип, на который указывает this, т.е. сам класс.</div><div class="code_line">&nbsp;&nbsp; Метод является visit-методом в паттерне Visitor. Он получает свой конкретный акцептор, должен</div><div class="code_line">&nbsp;&nbsp; запросить (static_cast&#60;&#62;-ом) у него конкретно свой интерфейс и вызвать его, сообщив т.с. свой</div><div class="code_line">&nbsp;&nbsp; динамический тип. Фактически static_cast&#60;&#62; отбирает из всего дерева интерфейсов свой, что и</div><div class="code_line">&nbsp;&nbsp; является восстановлением его динамического типа, а вызов Accept() сообщает его конкретному</div><div class="code_line">&nbsp;&nbsp; акцептору, бросая управление в реализующий этот интерфейс метод где-то в линейной иерархии его</div><div class="code_line">&nbsp;&nbsp; узлов.</div><div class="code_line">&nbsp;&nbsp; Проблема тут в том, чтобы создать для visit-метода правильную сигнатуру. Пользователький код её</div><div class="code_line">&nbsp;&nbsp; не знает, т.к. типы абстрактных акцепторов генерируется самим прототипом. Поэтому приходится</div><div class="code_line">&nbsp;&nbsp; задействовать метакод для получения недостающих данных. */</div><div class="code_line">&nbsp;</div><div class="code_line">// Тело visit-метода</div><div class="code_line">#define MAKE_ACCEPTABLE_BODY(Proto, PList, Concrete) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;{ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;return static_cast&#60;MultiMethods::details::Acceptor&#60;Concrete, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename Proto::ret_type&#62;&amp;&#62;(a).Accept(this); &nbsp;\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">// Объявление visit-метода в классе</div><div class="code_line">#define MAKE_ACCEPTABLE_DECL(Proto, PList, Concrete) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;virtual typename Proto::ret_type Accept(typename Proto::template getArg&#60;PList&#62;::type &amp;a);</div><div class="code_line">&nbsp;</div><div class="code_line">// Внутриклассное определение visit-метода</div><div class="code_line">#define MAKE_ACCEPTABLE(Proto, PList, Concrete) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; \</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;virtual typename Proto::ret_type Accept(typename Proto::template getArg&#60;PList&#62;::type &amp;a) &nbsp;\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;MAKE_ACCEPTABLE_BODY(Proto, PList, Concrete)</div><div class="code_line">&nbsp;</div><div class="code_line">// Внеклассное определение visit-метода</div><div class="code_line">#define MAKE_ACCEPTABLE_IMPL(Proto, PList, Concrete) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typename Proto::ret_type Concrete::Accept(typename Proto::template getArg&#60;PList&#62;::type &amp;a)\</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;MAKE_ACCEPTABLE_BODY(Proto, PList, Concrete)</div><div class="code_line">&nbsp;</div><div class="code_line">#endif // MULTIMETHODS_H_0A0E1659_FD72_4B5B_A091_EF59C8050584</div></ol></div></div></div></div>Эти немного короче, потому что RTTI использовало больше кода в акцепторах. Даже не знаю, стоит ли описывать внутренности. Всё C++1x-овое описано <a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=413381' target='_blank'>в прошлой теме</a>, всё Visitor-ное – <a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=396031&hl=' target='_blank'>в старой C++03</a>, изменения и от той, и от другой покрыты предыдущим постом. Пожалуй, воздержусь от дополнительных комментариев. Просто напомню общий принцип. Абстрактный акцептор на основе списка типов иерархии объявляет дерево интерфейсов, узлы которого представлены шаблонным абстрактным классом Acceptor, параметризируемым типом класса из этой иерархии; конкретный акцептор на основе того же списка типов реализует эти интерфейсы, наследуясь от абстрактного. Абстрактный приходит в visit-метод параметра, тот его кастует к Acceptor&lt;&gt; своего типа, зовёт его метод, и тот всплывает в его реализации где-то в конкретном акцепторе, тем самым восстанавливая динамический тип параметра. Подробности достаточно хорошо описаны в теме версии C++03.<br>
Ниже те же тесты, но интрузивные.<br>
<br>
<span class="b-attach" data-size="8954" data-hits="109" data-attach-id="59113" data-attach-post-id="3776570">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3776570&amp;attach_id=59113' title='Скачать файл' target='_blank'>tests.zip</a> (, : 109)
		</span><br>
<span class="b-attach" data-size="3993" data-hits="108" data-attach-id="59114" data-attach-post-id="3776570">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3776570&amp;attach_id=59114' title='Скачать файл' target='_blank'>newTests.zip</a> (, : 108)
		</span><br>
<span class="b-attach" data-size="1576" data-hits="105" data-attach-id="59115" data-attach-post-id="3776570">
			<span class="b-attach__title"></span><a class='b-attach-link' href='https://forum.sources.ru/index.php?act=Attach&amp;type=post&amp;id=3776570&amp;attach_id=59115' title='Скачать файл' target='_blank'>testTimeVisit.zip</a> (, : 105)
		</span><br>
<br>
Замечу, что RTTI генерит меньше кода, но компилится дольше. Это заметно на высоко-арных мультиметодах.<br>
Я одно время размышлял, не стоит ли склеить обе версии в одну библиотеку. В конце-концов они разнятся только реализацией акцепторов, кои можно передать извне политикой. Передумал. Во-первых, они требуют чуть по-разному оформлять декларации диспетчеров и своих классов, во-вторых, у них всё ж разные свойства, примерно как у вектора с ассоциативным массивом. Так что пусть лучше будут две библиотеки. Другое дело, что надо бы было пространства имён по-разному обозвать... что-то не подумал сразу. Ну, я уверен, вы справитесь, а мне лениво перезаливать тесты, которые от таких перемен не будут компилиться.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776413</guid>
        <pubDate>Fri, 17 Aug 2018 13:25:14 +0000</pubDate>
        <title>Мультиметоды без RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413422&amp;view=findpost&amp;p=3776413</link>
        <description><![CDATA[Qraizer: В <a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=413381' target='_blank'>предыдущей теме</a> я получил то, что хотел: реализовал динамическую диспетчеризацию в ран-тайм с поддержкой фич C++0x. На этом можно было бы остановиться, однако сравнивать реализации C++03 с C++1x как-то некрасиво. Всё-таки работа, несвязанная с диспетчеризацией, разная и оформлена по-разному, поэтому в условиях высокой производительности visit-ного C++03 эта разница может составить существенную часть от общих временны́х ресурсов. В общем, я покумекал и решил, что интрузивный вариант тоже следует перенести под C++1x, тем более что в ряде случаев потеря производительности из-за RTTI и сам факт использования RTTI в приложении может оказаться неприемлемым, а терять поддержку C++1x из-за использования версии C++03 тоже не всем захочется.<br>
Благо в этом не было ничего особо сложного. Фактически работа диспетчера состоит из пяти этапов: предварительная обработка параметров, в ходе которой те приводятся к удобной для обработки виду, подготовка стартовых структур типов (большей частью ещё при компиляции), итерирование по параметрам, в ходе которого восстанавливаются и сохраняются в списке типов динамические типы переданных параметров, постобработка параметров, заключающаяся г.о. в приведению принятых типов к их восстановленным реальным, и вызов перекрытого мультиметода, в ходе которого компилятор разрешает перегрузку и выполняет восходящие неявные касты, если надо. Из этих пяти этапов последний вообще делает компилятор, выполнение итераций перекладываются на акцепторы, и им как бы пофик на то, что и как происходит вокруг них, а остальное не зависит от способа работы с полиморфными классами. Поэтому однажды перепроектировав пред- и пост- хендлинг параметров, я никак не затронул работу акцепторов, а значит перенести старые акцепторы под новый C++1x не должно составить труда, учитывая, что вся пред- и пост- обработка мною сознательно были выполнены т.о., чтобы не затронуть рабочие структуры акцепторов.<br>
Ну, как бы так и вышло. Всего лишь пришлось добавить форвард и универсальные ссылки в Accept()-ы акцепторов. Но вот основная проблема с сильной зависимостью диспетчера и определений visit-методов, о которой говорилось в прошлой теме, осталась, да ещё и в усугублённом качестве. Объявления visit-методов, т.к. они виртуальные, иначе какой же это Visitor, без полиморфизма-то, с одной стороны не могут быть шаблонными, с другой зависят от соответствующих им абстрактных акцепторов, т.к. принимают их параметром, значит определения классов не могут располагаться перед ними; с другой – если диспетчер к точке определения классов уже будет создан, он не будет иметь информации о взаимном родстве между классами одной иерархии, поэтому на финальном этапе работы диспетчера компилятор не сумеет выполнять неявные касты производных классов к базовым, значит определение диспетчера не может быть расположено перед определениями классов. Прямое противоречие. В версии C++03 это было проблемой, но проблемой решаемой, хотя и неудобно. Там пользователь посредством typedef LinkDynamic&lt;&gt; сам создавал типы абстрактных акцепторов, и они были отделены от диспетчера, поэтому можно было расположить определения классов между этими определениями. Но в новом интерфейсе пользователь больше не работает с акцепторами сам, диспетчер самостоятельно их создаёт на основе вариадика с параметрами. Поэтому я столкнулся с неприятной дилеммой: либо вернуть заботу об абстрактных акцепторах пользователю, либо искать иной путь. К счастью, второй вариант нашёлся. Пусть и не такой удобный, как с RTTI версией.<br>
Понятно, что по-любому придётся разделить акцепторы и диспетчер. Я решил, что введение понятия прототипа для мультиметода вполне укладывается в логику и не выглядит таким уж костылём. Поэтому тут теперь из mmethod.h экспортируются два шаблона: помимо собственно Dispatcher ещё и Prototype. Теперь всё ранее передаваемое Dispatcher без изменений нужно передавать в Prototype, создаваемый typedef, а Dispatcher-у указывать именно его.<br>
Вот тот же пример, что в прошлой теме.<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">/* Наши тестовые классы */</div><div class="code_line">class B1;</div><div class="code_line">class D11;</div><div class="code_line">class D12;</div><div class="code_line">class D13;</div><div class="code_line">class D14;</div><div class="code_line">&nbsp;</div><div class="code_line">class B2;</div><div class="code_line">class D21;</div><div class="code_line">class D22;</div><div class="code_line">class D23;</div><div class="code_line">&nbsp;</div><div class="code_line">typedef MM::MakeTList&#60;D13, D12, D11, B1, D14&#62; Param1List;</div><div class="code_line">typedef MM::MakeTList&#60;B2, &nbsp;D21, D22, D23&#62; &nbsp; &nbsp; Param2List;</div><div class="code_line">&nbsp;</div><div class="code_line">/* Прототип */</div><div class="code_line">class dispatchHere;</div><div class="code_line">typedef MM::Prototype&#60;dispatchHere, int, const Param2List*, std::string&amp;, Param1List&amp;&#62; Proto;</div></ol></div></div></div></div>Всё то же, но добавился прототип. Его сигнатура в точности такая же, как у диспетчера в той теме.<br>
<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">/* Определяем классы */</div><div class="code_line">/* Первая иерархия */</div><div class="code_line">class B1</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param1List, B1);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D11 : public B1</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param1List, D11);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D12 : public B1</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param1List, D12);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D13 : public D11</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param1List, D13);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D14 : public D12</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param1List, D14);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">/* Вторая иерархия */</div><div class="code_line">class B2</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param2List, B2);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D21 : public B2</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param2List, D21);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D22 : public D21</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param2List, D22);</div><div class="code_line">};</div><div class="code_line">&nbsp;</div><div class="code_line">class D23 : public B2</div><div class="code_line">{</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;MAKE_ACCEPTABLE(Proto, Param2List, D23);</div><div class="code_line">};</div></ol></div></div></div></div>Определения классов теперь включают знакомый макрос. Чуточку другой, правда. Об этом ниже.<br>
Контейнер с нашим базовым мультиметодом и его перекрытиями никак не изменился:<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">/* Контейнер с перекрытыми методами */</div><div class="code_line">struct dispatchHere</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;static int apply(const B2*, &nbsp;std::string&amp; str, &nbsp;B1&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple B2 -nonconst ref-B1 &nbsp;Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;0&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 31;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D21*, std::string&amp; str, &nbsp;B1&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D21-nonconst ref-B1 &nbsp;Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;1&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 32;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D22*, std::string&amp; str, D12&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D22-nonconst ref-D12 Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;2&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 33;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D22*, std::string&amp; str, &nbsp;B1&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D22-nonconst ref-B1 &nbsp;Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;3&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 34;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D23*, std::string&amp; str, &nbsp;B1&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D23-nonconst ref-B1 &nbsp;Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;4&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 35;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D23*, std::string&amp; str, D11&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D23-nonconst ref-D11 Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;5&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 36;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D23*, std::string&amp; str, D13&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D23-nonconst ref-D13 Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;6&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 37;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">&nbsp;&nbsp;static int apply(const D22*, std::string&amp; str, D14&amp;)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::cout &#60;&#60; &quot;Triple D22-nonconst ref-D14 Dispatch: &quot; &#60;&#60; &amp;str &#60;&#60; &quot; - &quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;str += &#39;7&#39;;</div><div class="code_line">&nbsp;&nbsp; &nbsp;return 38;</div><div class="code_line">&nbsp;&nbsp;}</div><div class="code_line">};</div></ol></div></div></div></div>Можно было бы не приводить и отослать в прошлую тему, но мне скопипастить не жалко.<br>
Наконец диспетчер:<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">/* Диспетчер */</div><div class="code_line">MM::Dispatcher&#60;Proto&#62; callThis;</div></ol></div></div></div></div>И снова мне не жалко скопипастить примеры вызовов:<div class='tag-code'><span class='pre_code'></span><div class='code  code_collapsed ' title='Подсветка синтаксиса доступна зарегистрированным участникам Форума.' style=''><div><div><ol type="1"><div class="code_line">&nbsp;&nbsp;B1 &nbsp;o1;</div><div class="code_line">&nbsp;&nbsp;D11 o11;</div><div class="code_line">&nbsp;&nbsp;D12 o12;</div><div class="code_line">&nbsp;&nbsp;D13 o13;</div><div class="code_line">&nbsp;&nbsp;D14 o14;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;B2 &nbsp;o2;</div><div class="code_line">&nbsp;&nbsp;D21 o21;</div><div class="code_line">&nbsp;&nbsp;D22 o22;</div><div class="code_line">&nbsp;&nbsp;D23 o23;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;std::string s = &quot; - it&#39;s the string&quot;;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; &quot;Before the passing into multimethod: &quot; &#60;&#60; s &#60;&#60; std::endl;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o2 , s, o12) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o21, s, o14) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o22, s, o12) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o22, s, o13) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o22, s, o14) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o23, s, o11) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o23, s, o12) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; callThis(&amp;o23, s, o13) &#60;&#60; &quot; returned&quot; &#60;&#60; std::endl;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;std::cout &#60;&#60; &quot;Outside a multimethod: &nbsp; &nbsp; &nbsp; &quot; &#60;&#60; s &#60;&#60; std::endl;</div></ol></div></div></div></div>Замечу лишь, что в версии для C++03 диспетчер было можно даже создать до определения классов и перекрытий, важно лишь, чтобы он впервые вызван был после этого. Тут, увы, это не проканает, и не проканает с RTTI-версией: ранее список типов из абстрактных акцепторов передавался в диспетчер шаблонным параметром, и инстанцирование зависимых от него сущностей, а значит и создание мульти-VMT, откладывалось до первого требования посредством вызова operator(), несмотря на полиморфный код в doIt() и акцепторах, т.к. его использование зависело лишь от operator(), а теперь этот список либо создаётся (в RTTI-версии), либо импортируется из прототипа (в интрузивной версии) непосредственно при инстанцировании диспетчера, поэтому все зависящие от него сущности инстанцируются тоже сразу, ибо в VMT для линкера нужно предоставить место уже сейчас.<br>
Из того, что осталось – вид макроса MAKE_ACCEPTABLE(). Понятно, что коли мы уже не создаём акцепторы сами, то определение сигнатуры visit-метода становится нетривиальной задачей. Решить её на самом деле несложно: когда создавали мы, мы знали, что использовать; когда теперь создаёт прототип, то он и знает эти сигнатуры, так что спрашивать нужно у него. Для этого в нём предусмотрен несложный метаалгоритм getArg&lt;&gt;. Ему даётся список типов, описывающий иерархию, и он его ищет у себя, в параметрах акцепторов, где же именно тот, который на основе конкретно этой иерархии строился. Если нашёл, возвращает результатом, и уже оттуда можно получить и сигнатуру акцептора, и тип возвращаемого значения. Так что теперь макросу передаётся не возвращаемый тип и акцептор, а список типов иерархии и собственно прототип. Ну и сам класс, конечно, это не изменилось. Зато если вы ещё раньше, в версии C++03, не сделали себе два других макроса, то тут они же есть готовые: это MAKE_ACCEPTABLE_DECL(), который только объявляет visit-метод в предположении, что его определение будет позже и где-то, и его можно использовать вместо MAKE_ACCEPTABLE(), и MAKE_ACCEPTABLE_IMPL(), который нужно ставить вне класса, и который собственно это определение и создаёт. Использование этих двух макросов вместо оригинального одного позволяет разделить visit-метод на объявление и определение и в итоге вынести последнее, например, из .h в .cpp.<br>
Остаётся лишь один вопрос... нет, два: что делать, если тип параметра входит в сигнатуру мультиметода более одного раза, и что делать, если одинаковые типы параметров используются разными мультиметодами, естественно с разными прототипами. Ответ на оба вопроса: ничего. Важно, чтобы список типов иерархии был верным, и в прототипе этот список фигурировал. Абстрактные акцепторы на основе одного и того же списка типов инстанцируются всё равно одинаковые, это вот конкретные могут отличаться, так что макросам пофигу, сколько раз этот список типов входит в прототип, и в какой именно прототип. И даже пофигу, каким именно образом передаётся фактический параметр: то ли про ссылке, то ли по указатели, то ли константный, то ли нет, итп. В общем, смотрите нижележащие примеры (которые будут, обещаю), там никаких заморочек, и всё работает.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      </channel>
      </rss>
	