<?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=413381&amp;view=findpost&amp;p=3776287</guid>
        <pubDate>Wed, 15 Aug 2018 14:46:40 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776287</link>
        <description><![CDATA[Qraizer: В заключение перепостчу примеры-тесты из темы о мультиметодах C++03, слегка передизайненные под новую версию.<br>
<br>
<span class="b-attach" data-size="8398" data-hits="112" data-attach-id="59099" data-attach-post-id="3776287">
			<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=3776287&amp;attach_id=59099' title='Скачать файл' target='_blank'>tests.zip</a> (, : 112)
		</span><br>
<br>
Тут всё без изменений, тестятся разные варианты типов параметров в разных местах, разные способы передачи возвращаемых значений и разные -арности мультиметодов. Не обессудьте, тесты создавались для внутреннего использования, и по-прежнему я тут поленился привести их вывод к некоему понятному виду. И если с динамически связываемыми параметрами всё ещё более-менее понятно, но корректность обработки статически связываемых параметров показана в cout-е довольно неинтуитивно. Но как примеры вполне подойдут.<br>
В примерах выше все динамически связываемые параметры без изменений передаются по cv-неквалифицированным указателям. Как это было и в версии для C++03. Я решил этого не менять, но создать отдельные тесты для разных всех остальных способов передачи, включая rvalue refs для статически связываемых. Вот они.<br>
<br>
<span class="b-attach" data-size="3480" data-hits="118" data-attach-id="59100" data-attach-post-id="3776287">
			<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=3776287&amp;attach_id=59100' title='Скачать файл' target='_blank'>newTests.zip</a> (, : 118)
		</span><br>
<br>
И наконец, с чего всё начиналось. Тест для измерения оверхеда диспетчера в наносекундах.<br>
<br>
<span class="b-attach" data-size="1363" data-hits="113" data-attach-id="59101" data-attach-post-id="3776287">
			<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=3776287&amp;attach_id=59101' title='Скачать файл' target='_blank'>testTimeRTTI.zip</a> (, : 113)
		</span><br>
<br>
Сам по себе он особо ничего не значит, а значит лишь в сравнении с чем-либо ещё. Ну, вы можете взять его и переделать под C++03, будет с чем сравнивать. Но я бы посоветовал подождать... <a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=413422' target='_blank'>ещё одной темы</a>.  ;)]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776246</guid>
        <pubDate>Tue, 14 Aug 2018 18:38:42 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776246</link>
        <description><![CDATA[Qraizer: Заждались, небось. Итак, краткое описание технологии.<br>
За основу архитектуры нового диспетчера взята версия от C++03. Из мелких изменений:<ul class="tag-list"><li>удалён шаблонный интерфейс абстрактного акцептора за ненадобностью;</li><li>убран базовый класс из конкретного акцептора динамически связываемых параметров, т.к. абстрактный акцептор больше не нужен, т.к. акцепторы больше не делятся на абстрактные и конкретные; точнее, остались только конкретные, но называть их так уже не вполне правильно, т.к. в C++03 конкретные реализовывали интерфейсы, определённые абстрактными, а тут чистых методов нет вообще, так что теперь это просто акцепторы;</li><li>сами акцепторы LinkStatic&lt;&gt; и LinkDynamic&lt;&gt; переместились в приватный интерфейс абстрактного диспетчера, что обусловлено тем, что пользователю больше не нужно самостоятельно определять тип связывания.</li></ul>В целом, кому понятно, как работала версия C++03, легко поймёт, как теперь это же работает тут. За подробностями отсылаю туда, и там же лучше задавать вопросы, если что всё ещё непонятно. А тут займёмся немелкими изменениями.<br>
Начнём с создания диспетчера. Он имеет конструктор, в чью задачу входит первая половина важной работы по созданию внутренней VMT: он строит прямоугольную матрицу RTTI-классов. Каждый параметр мультиметода имеет массив таких классов, по одному на элемент своей иерархии. Скажем, если параметром является иерархия из пяти классов, то и массив будет создан из пяти элементов. Это особенно актуально для динамически связываемых параметров, но и статически связываемые тоже имеют такой список (из одного элемента). За хранение этого массива ответственнен Sheet&lt;&gt;. Каждый такой массив (экземпляр Sheet) описывает один параметр мультиметода, все такие массивы как раз и составляют матрицу. Они хранятся в линейной иерархии Sheet: самый первый параметр в самом производном узле Sheet-ов, самый правый – в самом базовом. Такой принцип хранения очень удобен для рекурсивного обхода параметров диспетчером, просто на каждой итерации очередному акцептору передаётся базовый класс текущего Sheet.<br>
Сами Sheet-ы хранят массивы RTTI-классов длиной в длину списка типов иерархии соответствующего параметра. Элементами этого массива являются адаптеры над std::type_info. Адаптеры нужны, чтобы придать последним семантику значений, ибо стандартные std::type_info ею не обладают. До кучи этот адаптер определяет operator&lt;() через std::type_info::before(), ну и другие полезные операции. Важной деталью адаптера является также индекс, который сначала совпадает с позицией класса в списке типов иерархии, но в дальнейшем массив сортируется для последующего бинарного поиска, а значит итоговые позиции классов в списке типов не обязаны будет совпадать с исходными индексами в массиве, поэтому для сохранения этой связи нужен индекс.<br>
Перейдём к вызову диспетчера. Перегруженный в диспетчере operator() теперь принимает вариадик rvalue ссылок. Его назначение – как и ранее, принять все параметры, положить в кортеж и запустить итерации восстановления динамических типов. Только теперь это делается в два приёма. Сам оператор () выполняет предобработку параметров и передаёт их методу decay(), и вот он как раз делает всё перечисленное. А предобработка – это новая функциональность, которая в версии C++03 была не нужна. Она заключается в том, чтобы<ol class="tag-list" type="1"><li>выполнить неявные касты статически связываемых параметров к типам их аргументов в соответствии с правилами Стандарта языка; так, можно под int передать какой-нибудь char или под std::string строковый литерал, однако нельзя, чтобы компилятор, например, смог заюзать каст-конструктор, если тот explicit;</li><li>выполнить каст динамически связываемых параметров к их самым базовым типам, при этом независимо от фактического способа передачи свести их внутри диспетчера к cv-неквалифицированным указателям; хотя это реализовано и топорно, это оказалось проще, чем параметризировать методы работы с ними на уровне политик.</li></ol>mkref&lt;&gt; занимается большей частью вторым пунктом, а static_cast&lt;&gt; первым. Но и вторым тоже, ибо а вдруг базовый класс приватный. Метод decay() же получает на входе вариадик уже готовых параметров, и ему остаётся лишь на основе вариадика типов мультиметода сварганить тип кортежа, создать его на стеке, инициализировать вариадиком своих параметров и передать в первую итерацию восстановления типов.<br>
Первая итерация выполняется в doIt(). Он создаёт акцептор для первого аргумента мультиметода, выполняет восстановление динамического типа первого параметра и вызывает по восстановленному типу нужный его Accept(). Остальные итерации выполняются уже внутри этих Accept(), и они полностью аналогичны первой итерации, только параметры и аргументы у каждого свои. Только акцептор для самого последнего аргумента отличается от предыдущих, т.к. у него другая задача: ему ничего не нужно восстанавливать, всё восстановлено до него; вместо этого ему нужно вызвать конкретный диспетчер, чтобы тот собрал в одну кучу восстановленное и осуществил выбор между перекрытыми мультиметодами. Но о нём потом, сейчас интересно, как осуществляется восстановление динамических типов, и это тема для отдельного абзаца.<br>
Каждый такой акцептор имеет имя, начинающиеся на Iter, и представляет собой в целом такую же иерархию, как и конкретный акцептор в версии для C++03. Каждый рабочий узел в нём называется IterAcceptorCaller, которых в иерархии несколько, для каждого типа из списка типов узел свой, базовым для которого является IterAcceptorCaller для следующего типа из этого же списка. Узел для самого последнего типа больше не нуждается в базовых классах, т.к. абстрактных акцепторов в этой реализации нет. (На самом деле базовый класс у него есть, но у него отдельная задача, описываемая парой предложений ниже.) Каждый IterAcceptorCaller в иерархии т.о. обслуживает свой тип в списке типов и при этом имеет свой Accept(). Конструктор каждого узла принимает вариадик из указателей на эти методы от более производных узлов и добавляет к нему свой. В результате самый базовый IterAcceptorCaller, которому в списке типов обслуживаемой им иерархии сопоставляется NullType, получает полный комплект таких указателей. Вот их, родимых, он и помещает в свой массив (длиной в длину списка типов иерархии обслуживаемого этим акцептором параметра), чем выполняет вторую половину работы по созданию внутренней VMT. В отличие от первой половины, эту половину нельзя выполнить при создании диспетчера в его конструкторе, т.к. набор генерируемых акцепторов создаётся только при вызове диспетчера, а не заранее, причём создаются все акцепторы на стеке, что делает диспетчер абсолютно потокобезопасным. Чтобы вторую половину тоже можно было сделать в конструкторе диспетчера, его архитектуру придётся существенно изменить, учесть, что одинаковые акцепторы могут входить в VMT несколько раз (т.к. у мультиметода могут быть одинаковые типы параметров) и, т.к. хранить все данные придётся в полях диспетчера, придётся озаботиться потоковой безопасностью, и при этом кортеж всё равно будет на стеке, т.к. его контент определяется только в точке вызова диспетчера. В общем, овчинка выделки не стоит, т.к. создание массива из указателей на методы задача весьма дешёвая, и её вполне можно позволить себе в ран-тайм. Делает он это не совсем чисто, т.к. я внезапно обнаружил, что распоследние версии VS и Intel Compiler ещё не понимают fold-expression из C++17. Там (точнее в LastAcceptorCaller) приводится вид метода getArgs(), который строит такой массив очень изящно, да и вообще, fold-expression были бы полезны ещё кое-где по диспетчеру, на минимум в трёх местах, но увы, я решил, что было бы некрасиво вычёркивать из списка пользователей мультиметодов владельцев VisualStudio из-за нерасторопности MS и Intel. Так же замечу, что помимо специализированного самого базового IterAcceptorCaller, в иерархии акцептора есть ещё и специализированный самый производный, называемый просто IterStart. Он очень прост, и если бы не один-единственный фактик, он был бы не нужен. Но нужен, ибо фактик: все указатели на методы Accept() имеют разную квалификацию, так как принадлежат разным классам. Да, они все в пределах одной иерархии и поэтому могут быть вызваны, будучи правильно деквалифицированы подходящим образом static_cast&lt;&gt;нутым this. Вот в этом как раз и состоит предназначение IterStart: именно к его типу this всех указателей на Accept() и кастуются.<br>
Ну и пара слов касательно собственно восстановления динамического типа. У параметра берётся его typeid() и ищется в текущем Sheet. Ищется посредством std::lower_bound(), который, увы, не обязан давать точное значение, ему вполне достаточно указать на точку в массиве, где оно должно было бы быть, если точного значения не нашлось. По идее, такого быть не должно, однако пользователь вполне может ошибиться либо с определением списка типов иерархии, либо указал класс вместо списка типов иерархии, либо просто с параметром, тупо передав не тот экземпляр. В общем, после std::lower_bound() нужно убедиться, что искомое вообще-то нашлось, и ежели вдруг нет, ловите std::invalid_argument(). Можно было бы, конечно, взять ближайший... вот только RTTI никак не регламентирует метод упорядочивания, используемый std::type_info::before(), и вряд ли будет хорошо, если при подобных ошибках пользователя диспетчер реализовал бы implementation defined behaviour. Да и вообще, у RTTI нельзя спросить &quot;кто это?&quot;, а можно лишь &quot;а вот это вот не вот этот ли случаем?&quot; и получить лишь булевый ответ. ...И не надо мне тут советовать ещё и свою RTTI мутить вместо стандартной, и своей VMT за глаза достаточно. В общем, убедившись, что всё нашлось, остаётся лишь вытащить из указанного std::lower_bound() экземпляра RTTI класса его исходный индекс в списке типов иерархии и сындексировать указатель на Accept(), разыменовав его this-ом от IterStart. Профит, вызвали Accept() узла, ответственного за репрезентацию динамического типа параметра, и можем переходить к следующему аргументу мультиметода. Замечу, что для статически связываемых параметров всё это выполняется точно так же в полной мере. Просто для них список типов состоит из одного узла, поэтому выбор производится ...ну, из одного элемента. Я не стал отдельно оптимизировать этот случай, т.к. профита это даст в малоосязаемом количестве, компилятор и сам неплохо справляется с тривиальными случаями. Для них не надо восстанавливать динамический тип, т.к. позднее связывание для них не требуется. Вместо этого тип просто берётся из списка параметров мультиметода и остаётся неизменным. Если тип фактически переданного в диспетчер параметра неприводим к типу аргумента, компиляция провалится ещё в operator() абстрактного диспетчера, а если приводим, причём неявно, то уже в decay() он будет приведён к целевому типу.<br>
Последний по списку акцептор состоит из узлов LastAcceptorCalled. Строятся они по тому же принципу, что и для IterAcceptorCalled, включая самый производный LastStart, потому что восстановление типа, выполняемое предыдущим акцептором, его тоже касается, но его задача иная: получив управление в одном из своих Accept(), ему остаётся лишь вызвать конкретный диспетчер. Он представлен классом CallConcrete, и его задача заключается в получении списка восстановленных динамических типов, преобразовании значений из кортежа обратно в вариадик с кастом к восстановленным типам и вызове подходящего apply() из пользовательского контейнера с перекрытиями мультиметода. Каст выполняется static_cast&lt;&gt; даже для динамически связываемых параметров, несмотря на то, что каст нисходящий. Тем не менее, это безопасный каст, т.к. подсистема RTTI гарантирует, что объект на самом деле имеет целевой для static_cast&lt;&gt; тип, в противном случае ещё раньше вылетел бы std::invalid_argument(). Для статически связываемых параметров в этой точке получается identical conversion. Методы CallConcrete&lt;&gt;::apply&lt;&gt;::call() последовательно выбирают и обрабатывают поля кортежа, и когда те заканчиваются, срабатывает специализация CallConcrete&lt;&gt;::apply&lt;&gt; по пустому списку восстановленных типов, где call() в итоге вызывает перегруженные apply() в контейнере перекрытых мультиметодов, предварительно применив к каждому параметру постобработку. Постобработка требуется для обратного преобразования cv-неквалифицированных указателей на динамически связываемые параметры, которые именно в таком виде хранятся в кортеже и были предобработаны в mkref&lt;&gt; в operator(), обратно в их исходные представления на основе исходных типов из вариадика параметров мультиметода, для чего в CallConcrete этот вариадик тоже передаётся, а занимается этим dcref&lt;&gt;. В итоге получается вызов статического метода apply() нашего контейнера перекрытий, в который приходят все исходные, полученные абстрактным диспетчером, преобразованные к их реальным динамическим типам, в результате компилятор вынужден разрешить перегрузку этих apply(), и вуаля, цель достигнута.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776082</guid>
        <pubDate>Sat, 11 Aug 2018 21:26:32 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776082</link>
        <description><![CDATA[Qraizer: <strong class='tag-b'>Списки типов (tlist.h).</strong> Практически не изменились. Добавился лишь хелпер MakeTList&lt;&gt; для нерекурсивного создания списков через вариадики. Метаалгоритм GenHierarchy в RTTI-реализации не используется, однако оставил ради Visitor-реализации.<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><script>preloadCodeButtons('1');</script><br>
<strong class='tag-b'>Кортежи (tuple.h).</strong> Тут изменений больше, т.к. поля теперь хранятся в rvalue refs, и нет необходимости копипастить конструкторы, ибо вариадики же. Тут уже можно было использовать стандартные кортежи из std, всё ж таки не boost, но это опять-таки значило изменить архитектуру движка диспетчера. Не стал. Хотите – на здоровье.<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><br>
<strong class='tag-b'>Мультиметоды (mmethod.h).</strong> Вот тут изменений ожидаемо больше.<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_E689D195_5567_4BB4_8DFA_F4B111F69D92</div><div class="code_line">#define MULTIMETHODS_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div><div class="code_line">&nbsp;</div><div class="code_line">#include &#60;algorithm&#62;</div><div class="code_line">#include &#60;stdexcept&#62;</div><div class="code_line">#include &#60;typeinfo&#62;</div><div class="code_line">#include &#60;utility&#62;</div><div class="code_line">#</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">/* Строит список типов параметров &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">/* Класс-обёртка над std::type_info, позволяющая работать с ними в семантике значений.</div><div class="code_line">&nbsp;&nbsp; Хранит ссылку (точнее, указатель, чтобы не заморачиваться спец.методами и позволить</div><div class="code_line">&nbsp;&nbsp; компилятору самому их сгенерировать) на оригинальный std::type_info. Это в рамках</div><div class="code_line">&nbsp;&nbsp; Стандарта, т.к. объекты std::type_info имеют время жизни до конца программы. */</div><div class="code_line">class TypeInfo</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;const std::type_info *info;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;int &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ind; &nbsp; &nbsp;// исходный индекс в списке типов, ибо после сортировки</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// экземпляры в массиве перемешаются</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TypeInfo(): /* DefaultConstructable */ &nbsp; &nbsp; &nbsp; &nbsp; info(&amp;typeid(void)), ind(0) &nbsp; {}</div><div class="code_line">&nbsp;&nbsp;explicit TypeInfo(const std::type_info&amp; ti, int idx=0): info(&amp;ti), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ind(idx) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;bool operator==(const &nbsp; &nbsp; &nbsp;TypeInfo&amp; &nbsp;ti) const { return *info == *ti.info; }</div><div class="code_line">&nbsp;&nbsp;bool operator!=(const &nbsp; &nbsp; &nbsp;TypeInfo&amp; &nbsp;ti) const { return *info != *ti.info; }</div><div class="code_line">&nbsp;&nbsp;bool operator==(const std::type_info&amp; ti) const { return *info == &nbsp;ti; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;bool operator!=(const std::type_info&amp; ti) const { return *info != &nbsp;ti; &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;bool operator&#60; (const &nbsp; &nbsp; &nbsp;TypeInfo&amp; &nbsp;ti) const { return info-&#62;before(*ti.info); }</div><div class="code_line">&nbsp;&nbsp;bool operator&#60; (const std::type_info&amp; ti) const { return info-&#62;before( ti); &nbsp; &nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp;int &nbsp;index() const { return ind; }</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; **************</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</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;/* Генератор конкретных акцепторов, реализующих чистые методы абстрактных акцепторов.</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;template &#60;typename T,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;template &#60;typename, 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, typename SHT&#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, SHT&#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">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Получить RTTI параметра. Для динамического акцептора объекты хранятся по указателю,</div><div class="code_line">&nbsp;&nbsp; &nbsp; соответственно параметр нужно разыменовать, иначе вернётся RTTI указателя. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const std::type_info&amp; deref(T* &amp;&amp;t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { return typeid(*t); }</div><div class="code_line">&nbsp;&nbsp;/* Для динамически связываемых параметров тип может и не найтись из-за ошибки программиста,</div><div class="code_line">&nbsp;&nbsp; &nbsp; так что проверка на точное соответствие важна. */</div><div class="code_line">&nbsp;&nbsp;static &nbsp; &nbsp; &nbsp; bool &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;check(const TypeInfo&amp; l, const std::type_info&amp; r) { return l == r; &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;- тип возвращаемого значения мультиметода. */</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; &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, typename&#62; class GA,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename ATL, typename CTL, typename TPL, typename SRC, typename SHT&#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, SHT&#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">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Получить RTTI параметра. Для статического акцептора объекты хранятся по rvalue ссылке,</div><div class="code_line">&nbsp;&nbsp; &nbsp; соответственно разыменовывать ничего не надо, а rvalue ref скрывает любые cv-квалификаторы,</div><div class="code_line">&nbsp;&nbsp; &nbsp; поэтому не надо опасаться, что вместо RTTI параметра будет возвращено RTTI на его cv- или ref,</div><div class="code_line">&nbsp;&nbsp; &nbsp; главное только не форвардить. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T&#62;</div><div class="code_line">&nbsp;&nbsp;static const std::type_info&amp; deref(T &amp;&amp;t) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{ return typeid(t); }</div><div class="code_line">&nbsp;&nbsp;/* В списке типов только один тип, а его несоответствие, ежели вдруг, будет выявлено</div><div class="code_line">&nbsp;&nbsp; &nbsp; ещё при компиляции. */</div><div class="code_line">&nbsp;&nbsp;static &nbsp; &nbsp; &nbsp; bool &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;check(const TypeInfo&amp;, const std::type_info&amp;) { return true; &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;Создание внутренней VMT, основанной на RTTI. &nbsp; &nbsp; *************</div><div class="code_line">************** &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Часть I &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">/* Построение массива на экземплярах RTTI-класса. Рекурсию можно было бы переписать на вариадиках,</div><div class="code_line">&nbsp;&nbsp; однако сейчас это уже невозможно, т.к. исходные вариадики заменены на список типов. Кроме того,</div><div class="code_line">&nbsp;&nbsp; исходно вариадики тут могут быть задействованы только с C++17, т.к. ранее fold-expression</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; &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; функций частичных специализаций не предусмотрено, а полная специализация</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; была бы возможна, если исключить последний параметр, но для этого makeSheet()</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; нужно было бы сделать методом Sheet, где явные специализации запрещены</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &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; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; типа приходится сохранять в самом экземпляре RTTI-класса;</div><div class="code_line">&nbsp;&nbsp; третий параметр - массив экземпляров RTTI-класса. */</div><div class="code_line">template &#60;typename Tl, typename T, size_t N&#62; void makeSheet(Tl, int idx, T (&amp;row)[N])</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;row[idx] = TypeInfo(typeid(typename Tl::Head), idx);</div><div class="code_line">&nbsp;&nbsp;makeSheet(typename Tl::Tail(), idx+1, row);</div><div class="code_line">}</div><div class="code_line">// Стоп рекурсии. Можно вписать assert для контроля N... если вы параноик.</div><div class="code_line">template&#60;typename T, size_t N&#62; void makeSheet(NullType, int, T (&amp;)[N]) {}</div><div class="code_line">&nbsp;</div><div class="code_line">/* Класс-обёртка над массивами экземпляров RTTI-класса.</div><div class="code_line">&nbsp;&nbsp; Хранит по массиву на каждый параметр мультиметода: массив для следующего параметра лежит в</div><div class="code_line">&nbsp;&nbsp; базовом классе массива для текущего. */</div><div class="code_line">template &#60;typename Tl&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;class Sheet;</div><div class="code_line">template &#60;typename L, typename R&#62; class Sheet&#60;TList&#60;L, R&#62;&#62;: public Sheet&#60;R&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;TypeInfo row[Length&#60;typename L::TypeList&#62;::value];</div><div class="code_line">&nbsp;</div><div class="code_line">public:</div><div class="code_line">&nbsp;&nbsp;typedef Sheet&#60;R&#62; base_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;Sheet() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // базовые классы уже построили и отсортировали свои массивы</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;makeSheet(typename L::TypeList(), 0, row); &nbsp;// строим массив</div><div class="code_line">&nbsp;&nbsp; &nbsp;std::sort(std::begin(row), std::end(row)); &nbsp;// и сортируем</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;// RTTI-классов известной размерности.</div><div class="code_line">&nbsp;&nbsp;// Можно было бы ограничиться публикацией row[], однако хочется его константности, а делать</div><div class="code_line">&nbsp;&nbsp;// row[] константным нельзя, т.к. он инициализируется в теле конструктора, а не инициализатором.</div><div class="code_line">&nbsp;&nbsp;const TypeInfo (&amp;get()const)[Length&#60;typename L::TypeList&#62;::value] { return row; }</div><div class="code_line">};</div><div class="code_line">template &#60;&#62; class Sheet&#60;NullType&#62;{};</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; второй &nbsp; &nbsp;- тип возвращаемого мультиметодом значения,</div><div class="code_line">&nbsp;&nbsp; третий... - типы параметров. */</div><div class="code_line">template &#60;typename DI, typename ret_type, typename ...Args&#62;</div><div class="code_line">class Dispatcher</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;// преобразовать типы параметров мультиметода в аргументы</div><div class="code_line">&nbsp;&nbsp;typedef typename details::MakeParams&#60;ret_type, Args...&#62;::type TTl;</div><div class="code_line">&nbsp;&nbsp;typedef &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;details::Sheet&#60;TTl&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sheet_type; &nbsp; &nbsp;// тип RTTI-&quot;матрицы&quot;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// массивы экземпляров RTTI-класса, хранящие RTTI всех классов каждого параметра из ...Args</div><div class="code_line">&nbsp;&nbsp;const sheet_type sheet;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;/* Акцепторы. IterXXX обрабатывает все параметры, кроме последнего, LastXXX обрабатывает</div><div class="code_line">&nbsp;&nbsp; &nbsp; последний параметр. YYYYStart нужен для CRTP: методы всех YYYYAcceptorCaller приводятся</div><div class="code_line">&nbsp;&nbsp; &nbsp; к методам YYYYStart, что делает их имеющих единый квалифицирующий класс. */</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename CTL, typename PTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TPL, typename SRC, typename SHT&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct IterStart;</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename CTL, typename PTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TPL, typename SRC, typename SHT, typename MD&#62; &nbsp;struct IterAcceptorCaller;</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename CTL, typename PTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TPL, typename SRC, typename SHT&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct LastStart;</div><div class="code_line">&nbsp;&nbsp;template &#60;typename T, typename ATL, typename CTL, typename PTL,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename TPL, typename SRC, typename SHT, typename MD&#62; &nbsp;struct LastAcceptorCaller;</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 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, typename SHT&#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, typename SHT&#62; struct AcceptorMaker</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;&#60;T, TList&#60;AL, AR&#62;, PTL, TPL, SRC, SHT&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename AL::template MakeAcceptor&#60;T, IterStart,</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, SHT&#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, typename SHT&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; struct AcceptorMaker</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;&#60;T, TList&#60;AL, NullType&#62;, PTL, TPL, SRC, SHT&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename AL::template MakeAcceptor&#60;T, LastStart,</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, SHT&#62;::type type;</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">/********************************************************************************\</div><div class="code_line">************** &nbsp; &nbsp; &nbsp;Создание внутренней VMT, основанной на RTTI. &nbsp; &nbsp; *************</div><div class="code_line">************** &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Часть II. &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">&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; в списке, восстановлении динамического типа параметра по его RTTI и вызову того акцептора,</div><div class="code_line">&nbsp;&nbsp; &nbsp; который сопоставлен этому классу, для чего используются связь по индексам массива методов и</div><div class="code_line">&nbsp;&nbsp; &nbsp; исходного (несортированного) массива RTTI-классов.</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;&nbsp; &nbsp; - срез тип RTTI-&quot;матрицы&quot;;</div><div class="code_line">&nbsp;&nbsp; &nbsp; - самый производный акцептор (YYYYStart). */</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,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename SHT, typename MD&#62;</div><div class="code_line">&nbsp;&nbsp;struct LastAcceptorCaller&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT, MD&#62;:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public LastAcceptorCaller&#60;ret_type, R, CTL, PTL, TPL, SRC, SHT, MD&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef LastAcceptorCaller&#60;ret_type, R, &nbsp;CTL, PTL, TPL, SRC, SHT, MD&#62; base_type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;L&#62;::type &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; arg_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// конструктор строит вариадик из указателей на методы Accept()</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;LastAcceptorCaller(SRC&amp; ptl, TPL&amp; src, const SHT&amp; sht, A&amp;&amp;... args):</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;base_type(ptl, src, sht, std::forward&#60;A&#62;(args)...,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;static_cast&#60;ret_type (MD::*)(param_type)&#62;(&amp;LastAcceptorCaller::Accept)) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// восстановление типа последнего параметра и вызов нужной специализации конкретного диспетчера</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename MostBase&#60;typename CTL::Head::TypeList&#62;::type &nbsp; most_base;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;most_base&#62;::type param_type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ret_type Accept(param_type obj)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;arg_type arg = static_cast&#60;arg_type&#62;(obj); &nbsp; &nbsp; &nbsp; &nbsp;// восстановленый тип</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// вызвать конкретный диспетчер; т.к. восстановленные типы в PTL лежат в обратном порядке,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// последний восстановленный тип должен быть обработан специальным образом, поэтому</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// передаётся отдельно от RTL и кортежа.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return CallConcrete&#60;DI, ret_type, 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;(arg));</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;// классами, так что этот с ними уже не работает, он только обслуживает внутреннюю VMT</div><div class="code_line">&nbsp;&nbsp;template &#60;typename CTL, typename PTL, typename TPL, typename SRC, typename SHT, typename MD&#62;</div><div class="code_line">&nbsp;&nbsp;struct LastAcceptorCaller&#60;ret_type, NullType, CTL, PTL, TPL, SRC, SHT, MD&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename MostBase&#60;typename CTL::Head::TypeList&#62;::type &nbsp; most_base;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;most_base&#62;::type param_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;/* Построение массива методов для восстановления типа динамически связываемого параметра.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; Фактически, это внутренняя VMT. Для статически связываемого параметра массив состоит</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; из одного элемента.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; В C++17 и позже этот метод может быть реализован проще посредством fold-expression.</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; Ниже приводится его возможная реализация.</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; template &#60;std::size_t ...Ints, typename ...Args&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; void getArgs(std::index_sequence&#60;Ints...&#62;, Args ...args)</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; {</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; ((accepts[Ints] = args), ...);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; }</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; В более ранних C++1x приходится делать рекурсией, останавливаемой перегрузкой. */</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;int I, typename ...A&#62; void getArgs(ret_type (MD::*at)(param_type), A&amp;&amp;... args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;accepts[I] = at;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;getArgs&#60;I+1&#62;(std::forward&#60;A&#62;(args)...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;int I&#62; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;void getArgs(ret_type (MD::*at)(param_type))</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;accepts[I] = at;</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// конструктор строит внутреннюю VMT; закоменченный параметр тоже имеет отношение к fold-expression</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;LastAcceptorCaller(SRC&amp; ptl, TPL&amp;, const SHT&amp;, A&amp;&amp;... args): m_Params(ptl)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;getArgs&#60;0&#62;(/*std::index_sequence_for&#60;Args...&#62;(), */std::forward&#60;A&#62;(args)...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;SRC &m_Params; &nbsp; &nbsp; &nbsp;// исходный кортеж</div><div class="code_line">&nbsp;&nbsp; &nbsp;MD &nbsp;*self; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// LastStart</div><div class="code_line">&nbsp;&nbsp; &nbsp;// внутренняя VMT - массив методов Accept();</div><div class="code_line">&nbsp;&nbsp; &nbsp;// в отличие от RTTI-&quot;матрицы&quot; sheet, у каждого параметра мультиметода она своя и потому</div><div class="code_line">&nbsp;&nbsp; &nbsp;// должна строиться в run-time, чем конструкторы LastAcceptorCaller и занимаются</div><div class="code_line">&nbsp;&nbsp; &nbsp;ret_type (MD::*accepts[Length&#60;typename CTL::Head::TypeList&#62;::value])(param_type);</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// самый производный в иерархии акцептор; нужен для реализации CRTP, т.к. только тут все методы</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, typename SHT&#62;</div><div class="code_line">&nbsp;&nbsp;struct LastStart&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT&#62;:</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public LastAcceptorCaller&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT,</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;LastStart&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT&#62;&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef LastAcceptorCaller&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LastStart&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT&#62;&#62; base_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// поле self лежит в самом базовом акцепторе</div><div class="code_line">&nbsp;&nbsp; &nbsp;LastStart(SRC&amp; ptl, TPL&amp; src, const SHT&amp; sht): base_type(ptl, src, sht) { this-&#62;self = this; }</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;</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,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;typename SHT, typename MD&#62;</div><div class="code_line">&nbsp;&nbsp;struct IterAcceptorCaller&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT, MD&#62; :</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public IterAcceptorCaller&#60;ret_type, R, CTL, PTL, TPL, SRC, SHT, MD&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef IterAcceptorCaller&#60;ret_type, R, &nbsp;CTL, PTL, TPL, SRC, SHT, MD&#62; base_type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;L&#62;::type &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; arg_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// конструктор строит вариадик из указателей на методы Accept()</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;IterAcceptorCaller(SRC&amp; ptl, TPL&amp; src, const SHT&amp; sht, A&amp;&amp;... args):</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;base_type(ptl, src, sht, std::forward&#60;A&#62;(args)...,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;static_cast&#60;ret_type (MD::*)(param_type)&#62;(&amp;IterAcceptorCaller::Accept)) {}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;/* восстановление типа очередного параметра, генерация следующего акцептора, передача ему</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; следующего среза списка акцепторов, базовых типов параметров мультиметода, RTTI-матрицы итп</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; и накопленной восстановленной информации о динамических типах и его вызов. */</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename MostBase&#60;typename CTL::Head::TypeList&#62;::type &nbsp; most_base;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;most_base&#62;::type param_type;</div><div class="code_line">&nbsp;&nbsp; &nbsp;ret_type Accept(param_type arg)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typedef typename SHT::base_type SheetType;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;typedef typename AcceptorMaker&#60;ret_type, 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, SheetType&#62;::type acceptor;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &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;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; static_cast&#60;const SheetType&amp;&#62;(base_type::m_Sht));</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// поиск в RTTI-массиве элемента, соответствующего динамическому типу пришедшего в диспетчер</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// аргумента, и получение его индекса в исходном списке типов, описывающем его иерархию</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;auto idx = std::lower_bound(std::begin(base_type::m_Sht.get()), std::end(base_type::m_Sht.get()),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;details::TypeInfo(CTL::Tail::Head::deref(GetField&#60;0&#62;(base_type::m_Args))));</div><div class="code_line">&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; &nbsp;// успешно найден; в противном случае это означает ошибку в описании списка типов в иерархии</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;if ( idx == std::end(base_type::m_Sht.get()) ||</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;!CTL::Tail::Head::check(*idx, CTL::Tail::Head::deref(GetField&#60;0&#62;(base_type::m_Args))))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;throw std::invalid_argument(&quot;IterAcceptorCaller&#60;&#62; error: unlisted parameter&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// индексируем внутреннюю VMT, вызывая Accept() того акцептора, чей индекс вернул поиск</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// в RTTI-массиве, и передавая аргумент мультиметода, т.с. восстанавливая его тип;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;// в результате итерируемся к обработке следующего параметра</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;return (a.self -&#62;* a.accepts[idx-&#62;index()])(GetField&#60;0&#62;(base_type::m_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;// классами, так что этот с ними уже не работает, он только обслуживает внутреннюю VMT</div><div class="code_line">&nbsp;&nbsp;template &#60;typename CTL, typename PTL, typename TPL, typename SRC, typename SHT, typename MD&#62;</div><div class="code_line">&nbsp;&nbsp;struct IterAcceptorCaller&#60;ret_type, NullType, CTL, PTL, TPL, SRC, SHT, MD&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename MostBase&#60;typename CTL::Head::TypeList&#62;::type &nbsp; most_base;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename CTL::Head::template ParamType&#60;most_base&#62;::type param_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// Построение массива методов для восстановления типа динамически связываемого параметра.</div><div class="code_line">&nbsp;&nbsp; &nbsp;// См. также коммент к подобному методу в LastAcceptorCaller.</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;int I, typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;void getArgs(ret_type (MD::*at)(param_type), A&amp;&amp;... args)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;accepts[I] = at;</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;getArgs&#60;I+1&#62;(std::forward&#60;A&#62;(args)...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;int I&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;void getArgs(ret_type (MD::*at)(param_type))</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;accepts[I] = at;</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// конструктор, строит внутреннюю VMT</div><div class="code_line">&nbsp;&nbsp; &nbsp;template &#60;typename ...A&#62;</div><div class="code_line">&nbsp;&nbsp; &nbsp;IterAcceptorCaller(SRC&amp; ptl, TPL&amp; src, const SHT&amp; sht, A&amp;&amp;... args):</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;m_Params(ptl), m_Args(src), m_Sht(sht)</div><div class="code_line">&nbsp;&nbsp; &nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;getArgs&#60;0&#62;(std::forward&#60;A&#62;(args)...);</div><div class="code_line">&nbsp;&nbsp; &nbsp;}</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;SRC &m_Params; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// исходный кортеж</div><div class="code_line">&nbsp;&nbsp; &nbsp;TPL &m_Args; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// срез кортежа по текущий аргумент</div><div class="code_line">&nbsp;&nbsp; &nbsp;const SHT &m_Sht; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // срез RTTI-&quot;матрицы&quot;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;MD *self; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // IterStart</div><div class="code_line">&nbsp;&nbsp; &nbsp;// внутренняя VMT - массив методов Accept();</div><div class="code_line">&nbsp;&nbsp; &nbsp;// см. также коммент к подобному массиву в LastAcceptorCaller</div><div class="code_line">&nbsp;&nbsp; &nbsp;ret_type (MD::*accepts[Length&#60;typename CTL::Head::TypeList&#62;::value])(param_type);</div><div class="code_line">&nbsp;&nbsp;};</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;// самый производный в иерархии акцептор; нужен для реализации CRTP, см. коммент к LastStart</div><div class="code_line">&nbsp;&nbsp;template &#60;typename L, typename R, typename CTL, typename PTL, typename TPL, typename SRC, typename SHT&#62;</div><div class="code_line">&nbsp;&nbsp;struct IterStart&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT&#62; :</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;public IterAcceptorCaller&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT,</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;IterStart&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT&#62;&#62;</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef IterAcceptorCaller&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT,</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IterStart&#60;ret_type, TList&#60;L, R&#62;, CTL, PTL, TPL, SRC, SHT&#62;&#62; base_type;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;// поле self лежит в самом базовом акцепторе</div><div class="code_line">&nbsp;&nbsp; &nbsp;IterStart(SRC&amp; ptl, TPL&amp; src, const SHT&amp; sht): base_type(ptl, src, sht) { this-&#62;self = this; }</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;ret_type doIt(Tpl&amp; tpl)</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename Tpl::base_type &nbsp; &nbsp; &nbsp; &nbsp;TupleType; &nbsp; // срез кортежа</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename sheet_type::base_type SheetType; &nbsp; // срез RTTI-&quot;матрицы&quot;</div><div class="code_line">&nbsp;&nbsp; &nbsp;typedef typename AcceptorMaker&#60;ret_type, TTl, NullType, TupleType, Tpl, SheetType&#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), static_cast&#60;const SheetType&amp;&#62;(sheet));</div><div class="code_line">&nbsp;&nbsp; &nbsp;auto idx = std::lower_bound(std::begin(sheet.get()), std::end(sheet.get()),</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;details::TypeInfo(TTl::Head::deref(GetField&#60;0&#62;(tpl))));</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp; &nbsp;if ( idx == std::end(sheet.get()) ||</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;!TTl::Head::check(*idx, TTl::Head::deref(GetField&#60;0&#62;(tpl))))</div><div class="code_line">&nbsp;&nbsp; &nbsp; &nbsp;throw std::invalid_argument(&quot;doIt() error: unlisted parameter&quot;);</div><div class="code_line">&nbsp;&nbsp; &nbsp;return (a.self -&#62;* a.accepts[idx-&#62;index()])(GetField&#60;0&#62;(tpl));</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;ret_type 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;/* Точка вызова диспетчера. Аргументами могут прийти любые типы, т.к. они не обязаны строго</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 ret_type&#62;</div><div class="code_line">struct Dispatcher&#60;DI, ret_type&#62;</div><div class="code_line">{</div><div class="code_line">&nbsp;&nbsp;ret_type operator ()()</div><div class="code_line">&nbsp;&nbsp;{</div><div class="code_line">&nbsp;&nbsp; &nbsp;return CallConcrete&#60;DI, ret_type, 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">#endif // MULTIMETHODS_H_E689D195_5567_4BB4_8DFA_F4B111F69D92</div></ol></div></div></div></div><br>
<br>
Коменты к реализации coming soon.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776079</guid>
        <pubDate>Sat, 11 Aug 2018 19:41:09 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776079</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=413381&amp;view=findpost&amp;p=3776076</guid>
        <pubDate>Sat, 11 Aug 2018 17:36:15 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776076</link>
        <description><![CDATA[Qraizer: Хватит слов, пора за дело. Начнём с конца: сначала, как использовать. Вот пример из той темы:<br>
Предположим у нас есть две (несвязанных) иерархии полиморфных классов B1 и B2, и нам требуется мультиметод с такой сигнатурой:<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">int (virtual const B2*, std::string&amp;, virtual B1&amp;);</div></ol></div></div></div></div>Здесь по-прежнему virtual условно и показывает, что для этих параметров требуется позднее связывание. Заметьте, однако, что в демонстрационных целях я изменил способ передачи параметров. Ну, просто чтоб показать, что теперь позволяются не только cv-неквалифицированые поинтеры. Также будем считать, что перекрыть этот мультиметод нам понадобилось теми же сигнатурами, что и в том примере:<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">int (virtual const D21*, std::string&amp;, virtual &nbsp;B1&amp;);</div><div class="code_line">int (virtual const D22*, std::string&amp;, virtual D12&amp;);</div><div class="code_line">int (virtual const D22*, std::string&amp;, virtual &nbsp;B1&amp;);</div><div class="code_line">int (virtual const D23*, std::string&amp;, virtual &nbsp;B1&amp;);</div><div class="code_line">int (virtual const D23*, std::string&amp;, virtual D11&amp;);</div><div class="code_line">int (virtual const D23*, std::string&amp;, virtual D13&amp;);</div><div class="code_line">int (virtual const D22*, std::string&amp;, virtual D14&amp;);</div></ol></div></div></div></div>Итак, что для реализации этого нужно сделать? Та сущую ерунду.<ul class="tag-list"><li><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">#include &quot;mmethod.h&quot;</div><div class="code_line">&nbsp;</div><div class="code_line">namespace MM = MultiMethods;</div><div class="code_line">&nbsp;</div><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&lt;D13, D12, D11, B1, D14&gt; Param1List;</div><div class="code_line">typedef MM::MakeTList&lt;B2, &nbsp;D21, D22, D23&gt; &nbsp; &nbsp; Param2List;</div></ol></div></div></div></div>Что такое? :o Опять списки типов?? М-м-м... да. С этим, увы, ничего не поделать даже в C++17, т.к. по-прежнему пройтись по иерархии классов никаким метакодом невозможно. Тут возможно помогут лишь метаклассы из недавнего пропозала. Так что тему определения списков типов, описывающих иерархию динамически связываемых параметров, можно считать закрытой: они нужны, и ещё будут нужны по меньшей мере 8 лет. Но и хорошая новость: этими списками всё и ограничивается. Кроме того, обратите внимание, что список типов строится вариадиком, что всё-таки удобнее, чем было.</li><li>Далее определяем наши классы. Тут принципиально ничего не изменилось. Та же иерархия пустых классов, что в примере прошлой темы:<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;virtual ~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">class D12 : public B1 {};</div><div class="code_line">class D13 : public D11{};</div><div class="code_line">class D14 : public D12{};</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;virtual ~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">class D22 : public D21{};</div><div class="code_line">class D23 : public B2 {};</div></ol></div></div></div></div>Ну, нет макроса, внедряющего visit-метод за ненадобностью, и поэтому классы полиморфируются явно посредством виртуального деструктора. Понятно, что классы по-любому нужно как-то определить, так что эти определения непосредственно к мультиметодам не относятся.</li><li>Определение мультиметода и нескольких его перекрытий:<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">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 &lt;&lt; &quot;Triple B2 -nonconst ref-B1 &nbsp;Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D21-nonconst ref-B1 &nbsp;Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D22-nonconst ref-D12 Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D22-nonconst ref-B1 &nbsp;Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D23-nonconst ref-B1 &nbsp;Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D23-nonconst ref-D11 Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D23-nonconst ref-D13 Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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 &lt;&lt; &quot;Triple D22-nonconst ref-D14 Dispatch: &quot; &lt;&lt; &amp;str &lt;&lt; &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>И снова никаких изменений, кроме подправленных типов параметров вслед за изменённым прототипом мультиметода. И снова подобные действия нужно было бы выполнять в любом случае, так что и этот код относится к мультиметодам только лишь следованием требованию инкапсулировать мультиметод и все его перекрытия в одной структуре и реализовывать их статическими публичными (точнее, доступными) методами apply().</li><li>И напоследок создаём диспетчер:<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">MM::Dispatcher&lt;dispatchHere, int, const Param2List*, std::string&amp;, Param1List&amp;&gt; callThis;</div></ol></div></div></div></div>Всё. Как я и обещал, никаких списков, вариадики рулят. Обратите внимание, как определяются динамически связываемые параметры: списком типов иерархии. Зато всё остальное просто и понятно: первый параметр – наша инкапсулирующая структура, второй – возвращаемое значение, остальные – параметры в их исходных типах. Также обратите внимание, что без typedef из первого пункта можно было бы и обойтись:<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">MM::Dispatcher&lt;dispatchHere, int, const MM::MakeTList&lt;B2, &nbsp;D21, D22, D23&gt;::type*, std::string&amp;, MM::MakeTList&lt;D13, D12, D11, B1, D14&gt;::type&amp;&gt; callThis;</div></ol></div></div></div></div>просто с ними выглядит немного понятнее. Зато без них не будут нужны и опережающие объявления классов, так что первый пункт просто исчезает. В общем, решайте сами, как вам удобнее.</li><li>Использовать так же, как в том примере. Для удобства перепостчу сюда:<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 &lt;&lt; &quot;Before the passing into multimethod: &quot; &lt;&lt; s &lt;&lt; std::endl;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o2 , s, o12) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o21, s, o14) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o22, s, o12) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o22, s, o13) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o22, s, o14) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o23, s, o11) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o23, s, o12) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; callThis(&amp;o23, s, o13) &lt;&lt; &quot; returned&quot; &lt;&lt; std::endl;</div><div class="code_line">&nbsp;</div><div class="code_line">&nbsp;&nbsp;std::cout &lt;&lt; &quot;Outside a multimethod: &nbsp; &nbsp; &nbsp; &quot; &lt;&lt; s &lt;&lt; std::endl;</div></ol></div></div></div></div></li></ul>Ну как, сложно? Не правда ли, элементарно? А как насчёт посмотреть реализацию?]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776065</guid>
        <pubDate>Sat, 11 Aug 2018 14:00:24 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776065</link>
        <description><![CDATA[Qraizer: Чтобы испытать особую гордость нужно сравнить производительность с другими. Честно говоря, было лень делать глубокое исследование, поэтому порыскав по инету, нашёл более-менее простое <a class='tag-url' href='https://habr.com/post/155515/' target='_blank'>вот это</a>, которое не завелось из-за каких-то её внутренних проблем с boost::fusion. Мол, не может кастануть поинтеры на функции к константным поинтерам. Покопавшись с день, плюнул, ибо разбираться в её бустовой начинке не было никакого желания, и решил написать свою. Только лучше. Автор там явно признаёт, что у него сильные проблемы с производительностью, так как его диспетчер фактически делает попытки dynamic_cast&lt;&gt; до тех пор, либо пока не кончатся сортированные по порядку наследования типы, либо пока не проканает. В результате среднее количество кастов равняется половине глубины списка типов на каждый динамически связываемый параметр. Я же решил пойти другим путём, естественно, избавившись от самого сильного недостатка: интрузивности visit-метода. Сразу вопрос, а как сие сделать? Ибо если нельзя спросить у объекта &quot;ты кто?&quot;, тогда остаётся лишь спрашивать у кого-то ещё &quot;это кто?&quot;. Спрашивать, правда, особо не у кого, разве что у RTTI. Поэтому выбрал путь Александреску: бинарный поиск по сортированному контейнеру с предзаготовленными функциями для каждого динамического типа.<br>
Примерно за день придумал архитектуру, примерно через неделю она идеально работала. Сравнил производительность, подивился, ну и естественно немедленно возникло желание поделиться результатами. Вот только одно печалило: на дворе C++17, а код всё ещё 14-летней давности. Безобразие. В общем, взял себя в руки и решил-таки портировать на C++1x. Заодно избавившись и от других недостатков, конечно же, которые обусловлены ограничениями C++03.<br>
Процесс был довольно непростым. Так, я долго пытался на имеющемся движке диспетчера завести вариадики вместо списков типов, и в конце-концов понял, что овчинка выделки не стоит. Вариадики хороши для обобщённого кода, который ррраз&#33; и что-то сделал, но для метакода, реализующего нетривиальные алгоритмы, для которых характерны итерации и ветвления, они подходят плохо. По ним практически невозможно ничего специализировать, только параметризировать политиками каждый элемент предикатами. Которые хотя уже и можно специализировать, но код от этого яснее всё равно не становится, и получается шило с мылом. &lt;type_traits&gt; тоже остаётся не у дел, т.к. работает с типами, а не шаблонами. Попытки выразить его функционал через using опять-таки ничего не упрощают, а гораздо чаще наоборот. В общем, после месяца экспериментов с новой архитектурой ничего удобнее специализаций и рекурсии не придумалось, так что всё вернулось во круги своя: списки типов никуда не делись, движок остался прежним, а на вариадиках наверчен лишь внешний интерфейс диспетчеров. Формально, всё не так печально, конечно, и вариадики с предикатами вполне себе нормально бы зашли, но для этого пришлось бы в корне менять метаалгоритм. Кому вдруг приспичит, та за ради бога: код копилефт при условии сохранения исходного копирайта, который за мной с благодарностями в адрес <strong class='tag-b'>Flex Ferrum</strong>-а за идею Visitor-а.<br>
Так к середине зимы получилось избавить пользователей от лишних списков типов и typedef-ов, фактическую -арность сравнять с формальной, прикрутить форвард, что позволило не терять инфу о типах параметров по дороге от диспетчера до перекрытого мультиметода, и решить траблу с неявными кастами передаваемых в диспетчер параметров к заявленным типам аргументов мильтиметода, что на тот момент по-быстрому было реализовано через явные касты, что естественно расширяло диапазоны вольности компилятору, и это было нехорошо. Когда все некритичные унаследованные от C++03 недостатки были устранены, пришлось задуматься о нововведениях, иначе какой прок от порта, не реализующего новые фичи языка. Да, я о поддержке rvalue refs, и задуматься пришлось крепко. Причина задумчивости была в том, что rvalue refs на форварде неотличима от параметра-значения, и поэтому на классах в качестве параметров-значений движок постоянно норовил заюзать перемещающие конструкторы вместо копирующих. Попытки решить проблему быстро не увенчались успехом, так что я решил передохнуть.<br>
В лучших традициях той, C++03-ей, реализации, передох занял полгода. На минисейшоне в Москве во время второй моей командировки я-таки очередной раз взял себя в руки. В итоге проблему решил решать в лоб. И решил. Некрасиво, но снаружи не видно, да ещё и работает. Ещё долго, где-то с день, не решался, но всё-таки руки меня взяли, и я снял ограничение на тип динамически связываемых параметров. И снова вместо &lt;type_traits&gt; лобовое, тупое, но работающее решение. Зато удобно пользовать. Так что теперь они могут быть и ссылками, и cv-квалифицированными, и даже rvalue ссылками. Не могут только значениями, но это и понятно. Ну ещё нет cv-квалифицированных rvalue ссылок, потому что... оно кому надо? Не, я понимаю, что язык позволяет, но смысл? С моей точки зрения не больше, чем от cv-квалифицированных аргументов-значений. Опять-таки, копипаст ваш лучший друг, перфекционистам руки развязаны.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      <item>
        <guid isPermaLink='true'>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776039</guid>
        <pubDate>Fri, 10 Aug 2018 18:42:29 +0000</pubDate>
        <title>Мультиметоды на RTTI</title>
        <link>https://forum.sources.ru/index.php?showtopic=413381&amp;view=findpost&amp;p=3776039</link>
        <description><![CDATA[Qraizer: Прошло без малого 4 года, как предложенная мною реализация мультиметодов на C++03 была <a class='tag-url' href='http://forum.sources.ru/index.php?showtopic=396031&hl=' target='_blank'>выложена на всеобщее обозрение</a>. Она начиналась ещё во времена C++0x, когда ни C++11, ни компиляторов для C++11 ещё и в помине не было, а были только штучные бэтки с поддержкой нольИксового драфта. Собственно, поэтому и был выбран C++03, ибо даже после 11-го года предыдущий Стандарт ещё какое-то время был бы актуален, да и легаси проекты никуда не денутся. Занимался я ею от случая к случаю, потихоньку добавлял реализации тех или иных хотелок, уже и C++11 вполне себе состоялся и вовсю маячил С++14... в конце-концов на оставшиеся хотелки я просто плюнул и решил, что для C++03 и так сойдёт, надо на чём-то остановиться, ибо вот-вот, и мультиметоды появятся в языке нативные, а мне в каждом случае от случая всё сложнее вспоминать, на чём же я полгода назад остановился, и что ещё нужно сделать. Выложил, что к тому времени вышло.<br>
Нативных мультиметодов так и не дождались, так что в какой-то мере та тема всё ещё актуальна. Тем более, что если погуглить, то тема мультиметодов выглядит замусоленной по всем направлениям, хотя и достигнутым мною результатом по производительности и универсальности похвастаться смогут ой как немногие. Чего греха таить, я гордился своей реализацией. Ещё бы:<ul class="tag-list"><li>поддержка статически и динамически связываемых параметров;</li><li>поддержка любых типов для статически связываемых параметров;</li><li>формально неограниченная -арность;</li><li>хоть и многобуквенное, но логичное и интуитивное определение для диспетчера;</li><li>благодаря использованию правил перегрузки из Стандарта, диагностика о неоднозначном перекрытии мультиметода выдаётся ещё в compile-time;</li><li>инкапсуляция базового мультиметода и его перекрытий в рамках выделенной области видимости; для каждого мультиметода;</li><li>отсутствие любого RTTI, включая dynamic_cast&lt;&gt;, только static_cast&lt;&gt;; отсутствие reinterpret_cast&lt;&gt;; наличествует, правда, const_cast&lt;&gt;, снимающий константность, однако Стандарт это не нарушает, т.к. объекты со снятым const только хранятся по ссылкам, и нигде не пишутся, только читаются для передачи параметрами в перекрытый мультиметод;</li><li>мизерный оверхед – два полиморфных вызова на каждый динамически связываемый параметр + остальное легко оптимизируется средненьким оптимизатором, включая отсутствие лишних копирований аргументов-значений.</li></ul>Но и недостатков тоже хватало:<ul class="tag-list"><li>в связи с отсутствием вариадиков -арность фактически ограничена заимплеменченной копипастой; правда, она элементарно увеличивалась копипастой же, но всё-таки;</li><li>в той же связи от списков типов никуда не деться; а typedef-ов ещё больше, чем списков типов;</li><li>в связи с засильем typedef и списков типов определение диспетчера хоть и логичное и интуитивное, но сильно уж многобуквенное;</li><li>динамически связываемые параметры могут передаваться только по не cv-квалифицированным указателям;</li><li>за низкий оверхед приходится платить патерном Visitor, для чего в классы следует добавить visit-метод; его вид, впрочем, очень формален, так что его реализация легко укладывается в макрос, и тем не менее см.ниже;</li><li>большая сложность использования в несинтетических проектах из-за взаимной связи visit-методов в классах пользователя, которые нельзя определить до объявления параметров мультиметода, и диспетчером, который нельзя определить до определения классов; в одной единице трансляции это ещё несложно обходится, но в реальных проектах с документирующими интерфейсы классов заголовками и раздельными их реализациями соблюсти все нюансы порядка связанных с диспетчером объявлений/определений становится весьма непросто;</li><li>из-за отсутствия форварда в C++03 на входе в диспетчер теряется информация о типах параметров, ибо все они принимаются по const&amp;, поэтому в точке их принятия аргументами в перекрытом мультиметоде остаётся лишь надеяться, что программер нигде не ошибся в указаниях типов и передал то, что обещал; аукнуться может редко, в большинстве случаев компилер сообщит, ежели чё, но вот, например, по неконстантой ссылке передать rvalue вполне было можно;</li><li>при высокой -арности динамически связываемых параметров компилятор мог не найти для себя достаточно ресурсов или как минимум впасть в глубокую задумчивость; впрочем, тут влияет не столько -арность, сколько её комбинация с глубинами иерархий динамически связываемых параметров, однако попасть на такое несинтетически ещё над умудриться, ибо boost:spirit напрягает компилер заметно сильнее (не требуя, правда, баснословных ресурсов).</li></ul>Как бы немало, так что вопрос, а есть ли повод гордиться, то и дело меня занимал. Лично я считал, что да, финальная стоимость оверхеда с моей точки зрения перекрывает перечисленные неудобства, но всё не оставляла мысль, не обманываю ли я сам себя. Ведь как там говорится: любой уважающий себя программист должен написать <s class='tag-s'>мультиметоды</s>... а, не, там про тетрис. Ну тогда всё правильно, если б там мультиметоды, тогда в натуре гордиться особо было бы нечем. Но кроме гордости есть ещё особая гордость и исключительная гордость, а это уже понятия другого уровня.<br>
Вот так, примерно 9 месяцев назад, и вышло, что я взял себя в руки и начал себя испытывать. Ну, мультиметоды испытывать, в смысле.]]></description>
        <author>Qraizer</author>
        <category>C/C++: Общие вопросы</category>
      </item>
	
      </channel>
      </rss>
	