|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Дизайн и эволюция: перегрузка макросов10.02.2016, 04:10. Показов 8899. Ответов 17
Метки нет (Все метки)
Часть 0. Вместо предисловия.
всем привет. недавно, для одной из моих задач, мне потребовалось иметь возможность перегрузить макрос под разное количество аргументов. и хотя на самом деле препроцессор не поддерживает такую возможность. однако, существуют такие экзотические техники, которые позволяют провернуть подобное. у меня ушло некоторое время, что бы нагуглить портируемое решение: cl (msvc2012/msvc2013/msvc2015), mingw(481/492), gcc (493), clang (3.7.0) пришлось прочитать уйму материалов. и хотя прочитанные материалы сильно обогатили мои знания в области препроцессора, но все они без исключения были на английском языке. сами материалы преподносились довольно таки корявенько, поэтому, все равно пришлось сидеть и разбираться. я решил поделиться с сообществом, приобретенным знаниями, преподнося материал на русском языке, и достаточно подробно. так, что бы осилить его смог даже начинающий программист. итак, поехали. ------------------------------------------- Часть 1. Основа. для начала, нужно понять одно простое правило: как раскрываются макросы? что значит "раскрывается"? это значит, в то место, где был макрос, препроцессор подставляет результирующий текст. правило очень простое: препроцессор тупо подставляет кусок текста, который был указан при вызове макроса. если при раскрытии первого макроса, образовался текст вызова другого макроса, то происходит раскрытие и вложенного макроса тоже. и так до тех пор, пока все вложенные друг в друга макросы не раскроются, и не образуется окончательный текст. пример:
образовался текст вызова другого макроса. поэтому, препроцессор продолжил раскрывать уже вложенный макрос здесь ещё стоит обратить внимание, что буковка n внутри литерной константы была проигнорирована несмотря на то, что n - это аргумент макроса, который раскрывается в цыферки. собственно на этом вся великая магия препроцессора и заканчивается. однако этого оказалось вполне достаточно, что бы разные умельцы смогли проворачивать свои поехали дальше. ------------------------------------------- Часть 2. Макросы с переменным количеством аргументов. синтаксис очень простой:
мы можем передать неограниченное количество аргументов внутри макроса их обозначает специальный дефайн __VA_ARGS__ причем текст передается "как есть" со всеми указанными запятыми. __VA_ARGS__ - это на самом деле один такой неделимый аргумент. и если в дальнейшем передать его в макрос с двумя аргументами, то он будет интерпритироваться как один из аргументов такого макроса. то есть, при передаче его в другие макросы, он не раскрывается полностью в текст. это создает некоторые сложности. к этому мы ещё вернемся. теперь, прежде чем мы начнем перегружать макросы, нужно сначала научиться вычислять какое именно количество аргументов было переданно. ------------------------------------------- Часть 3. Определяем количество переданных аргументов. предупреждаю сразу, данный способ - ущербный. дело в том, что в макросы с переменным количеством аргументов, можно вообще вызывать без аргументов. в этом случае __VA_ARGS__ раскрывается в пустоту. нижеследующий способ не умеет обрабатывать такую ситуацию. далее, я покажу более правильный способ. но к нему мы придем постепенно: от более простого к сложному. итак, я просто покажу реализацию на примере. для наглядности я детально расписал каждый шаг раскрытия макросов. логика очень простая, вы сразу же её поймёте
собака зарыта в макросе CONVERT благодаря нему происходит формирование вызова макроса ARG_N он заставляет __VA_ARGS__ раскрыться в результирующий текст и таким образом образуется вызов макроса ARG_N с несколькими аргументами. ------------------------------------------- Часть 4. Zero предыдущая реализация не умеет определять количество аргументов равное нулю. что делает макрос не универсальным. однако есть одна хитрость, благодаря которой это можно исправить. если написать вот так:
то все выражение схлопнется, и образуется:
и это - кроссплатформенно. наверняка, человек который до такого додумался - настоящий ценитель! ("настоящими ценителями" я называю конченных извращенцев, если кто не понял) таким образом, предыдущую реализацию можно переписать вот так:
------------------------------------------- Часть 5. Перегрузка макросов. главная киллер-фича выше представленного способа: мы можем получать количество аргументов макроса времени препроцессирования. то бишь, получаемые циферки - это текст, который можно подмешивать при вызове других макросов. теперь мы готовы. суть идеи простая: допустим, у нас есть макрос:
мы уже умеем вычислять количество аргументов, переданное в макрос. из под главного макроса, просто сделаем вызов вложенного макроса-перегрузки подставив в его имя текст циферки - количество аргументов. а в качестве аргументов укажем __VA_ARGS__
я выделил общую одинаковую для разных макросов деталь. что бы максимум кода можно было вынести в библиотеку для повторного использования. от программиста требуется только описать сами перегрузки, трамплин для нуля аргументов, и префиксы имен перегрузок:
который послужил для меня первоисточником. http://stackoverflow.com/quest... h-c-macros на этом все. пока.
13
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
| 10.02.2016, 04:10 | |
|
Ответы с готовыми решениями:
17
[дизайн и эволюция] провалы в variadic конструкторы [Дизайн и эволюция] Дискриминация шаблона на примере макроса OUT_TO_STREAM Дизайн сайтов (desktop и адаптивный дизайн), баннеров и логотипов |
|
9 / 5 / 1
Регистрация: 15.08.2016
Сообщений: 48
|
|
| 15.10.2016, 13:41 | |
|
Сами по себе макросы - большое зло, а тут еще их перегрузка
0
|
|
|
|
||
| 15.10.2016, 19:27 | ||
|
C #define MACRO_0() ARG0 #define MACRO_1(n1) ARG1 n1 #define MACRO_2(n1,n2) ARG2 n1 n2 #define MACRO_3(n1,n2,n3) ARG3 n1 n2 n3 #define MACRO(n, ...) MACRO_##n (__VA_ARGS__) MACRO (0) MACRO (1, a) MACRO (2, a, b) MACRO (3, a, b, c) Code $ gcc t.c -E ARG0 ARG1 a ARG2 a b ARG3 a b c
1
|
||
|
|
||||||
| 22.06.2019, 01:38 | ||||||
|
Интересная тема, но чтото большая слишком простыня получается
я вообщето любитель, извените что влажу со своими пирогами но позвольте озвучить свою задачу и может быть найти решение задача : перезагрузить 0-2 аргумента МИНИМУМ количества строк. выше предложенный метод конверт или есть еще CONCAT не нравиться своей длиной пока что я сделал 4 строками но без нулнвого
1) можно это сделать менее чем 4 строки макроса ? 2) как перегрузить с 0 аргументом в следующей форме FOO() -> ABC() ?
0
|
||||||
| 09.06.2020, 14:52 | |||||||
Добавлено через 3 минуты Так что этот __VA_ARGS__ фигня полная умеет только цифры перебирать. И никакого толку от динамического количества аргументов нет.
0
|
|||||||
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
||||||||||||||||||||||
| 09.06.2020, 18:14 [ТС] | ||||||||||||||||||||||
dGET_ARGS_COUNT - макрос, который вычисляет кол-во аргументов dFOREACH - макрос, который в цикле умеет перебирать все переданные ему аргументы, и что-то с ними делать. кроме этого, становится возможным легко организовать различные перестановки. например: взять аргументы первого макроса, переставить их задом наперед, и скормить второму макросу. так же, становится возможным реализовать поддержку IF на макросах.что в свою очередь даёт возможность организовать циклы WHILE или FOR на макросах.лично мне на практике пригодилась возможность реализовывать различные комбинаторные алгоритмы. например:
(1,2)с каждым элементом второго кортежа: (3,4,5)и над этой парой выполняется действие, которое описано в макросе pp_macroвывод в консоль:
не обязательно кортежами. с точки зрения возможностей кодо-генерации: вооружившись циклами и условиями, можно сгенерировать текст любой сложности. по сути, фантазия программиста ограничена только максимальным кол-вом аргументов, которое можно передать в макрос: 127 штук.
0
|
||||||||||||||||||||||
| 09.06.2020, 18:30 | ||
|
Так что этот
__VA_ARGS__ фигня полная умеет только цифры перебирать.
for(;;)break;b+=10; ваши примеры это игра с цифрами и текстом а я спрашиваю о том что я запихиваю код в макрос а нутри он по порядку весь выполянется. Это походу интерпретация тут наверное только Пион сможет такое, хотя что сложного в том выполнить по порядку аргументы макроса но видимо сложно. Получается что эффективность макросов с неограниченными параметрами нулевая.
0
|
||
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
||
| 09.06.2020, 19:26 [ТС] | ||
|
во-первых, с чего ты взял, будто бы __VA_ARGS__ вообще что-то там перебирает?вот откуда в твоей голове взялся этот бред? во-вторых, вот с чего ты взял, что __VA_ARGS__ можно составить только из цифр?такое впечатление, что ты вообще не понимаешь, что такое __VA_ARGS__, и зачем он нужен. я думаю, тебе нужно открыть букварь, главу "препроцессор", и для начала изучить азы.
1
|
||
| 09.06.2020, 23:16 | ||
for(;;)break;b+=10;, __VA_ARGS__ тут не катит получается что он и создан для перебора цифр и букв, все примеры включая ваш примитивны, возможно потому что сами макросы таковы примитивны поэтому и нельзя выполнить такую строку ACTION(for(;;)break;,z); вызов должен быть for(;;)break;b+=10; это и есть написание текстового кода в макросе да даже такой код оно не выполнит ACTION(;,;,;);, как только программа натыкается на символ ; между запятыми сразу же облом, вот так вот а писать цифры это да можно и в функции для этого макрос не нужен.Макросы это первое с чем можно работать потому что остальное на много сложнее а макрос некий интерпретатор.
0
|
||
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
||||||||||||||||
| 09.06.2020, 23:42 [ТС] | ||||||||||||||||
0
|
||||||||||||||||
| 10.06.2020, 01:52 | |||
__VA_ARGS__ , а какая-нибудь другая запись.
for(;;)break; а потом происходит выход а потом выполняется этот код b+=10;( при этом b может быть как объявлено так и нет int b+=10;). Классная задумка да.
0
|
|||
|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
|||||||||||||||||||
| 10.06.2020, 05:26 [ТС] | |||||||||||||||||||
|
если в тексте каша, значит в голове тоже каша. какая ещё такая "другая" запись? ты сам то хоть понимаешь о чем думаешь? с чего ты взял своё "значит" ? однозначно, ты не открывал букварь. и не изучал основы препроцессора. иначе как ещё можно объяснить тот факт, что ты до сих пор так и не понял, что препроцессор тупо подставляет обычный текст? https://rextester.com/AUP28595
выложи человеческое словесное описание. выложи код, который не получается. но не нужно приходить в мою тему, и называть __VA_ARGS__ фигнёй только потому,что ты его не осилил.
0
|
|||||||||||||||||||
| 10.06.2020, 11:24 | ||
|
Не по теме:
Каюсь, отправил его сюда почитать...
0
|
||
| 10.06.2020, 11:39 | |||||||||||
|
А сделать такое сможет.
for(;;)break;, потом выполняется b+=10; у меня бывает нужда в таких конструкциях приходится по отдельности выполнять и цикл for(int q=-1;++q<3;) вызывать 2 раза, первый раз чтобы выполнить аргумент for(;;)break;, второй раз чтобы выполнить b+=10;. Мне нужно было сразу так объяснить.
0
|
|||||||||||
|
Неэпический
|
|||||||||||||
| 10.06.2020, 14:08 | |||||||||||||
|
Так что ли?
P.S. Там косяк с ;
Добавлено через 20 минут Чуть "модернизировал". Кажется, работает и это как раз то, чего ты хочешь. Но это не точно.
https://wandbox.org/permlink/O3PgHnM1QhjxyteZ
0
|
|||||||||||||
| 10.06.2020, 15:17 | |||||||||
|
Также я удаляю макросы
{} #undef EXECUTE_AUX_10 #undef EXECUTE_AUX_9 А ещё плохо что приходится писать EXECUTE_AUX_10/9/8 константность какаета. Добавлено через 2 минуты 5,4,3,2,1,0 делают программу не универсальной, хреново это конечно. Как вариант прямо в коде удалить и переписать макрос и тогда получиться динамический макрос
0
|
|||||||||
|
Неэпический
|
||
| 10.06.2020, 16:28 | ||
|
Короче, фигня всё это. Ты просто хочешь не нормального. Не по теме: Я когда-то генерировал макросами функции-члены в которых макросами генерировались лямбды и, так сказать, на собственной шкуре понял, что это говнокод редкостный.
0
|
||
| 10.06.2020, 16:55 | ||
#define EXECUTE_AUX_10/9/8 чтобы не писать все 10 штук и для функций это было бы классно. Ну тут по ходу уже ничего не сделаешь. Бывает даже функции пишешь int Int_1(){return 8;}Int_2()/3 и т.д. Вроде типа сделать чтобы всё было как массивы цифры.
0
|
||
| 10.06.2020, 16:55 | |
|
Помогаю со студенческими работами здесь
18
Дизайн выпадающего меню под дизайн обычного Эволюция Эволюция растений Эволюция и человек
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Налог на собак: https:/ / **********/ gallery/ V06K53e
Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf
Пост отсюда. . .
|
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop?
Ниже её машинный перевод.
После долгих разбирательств я наконец-то вернула себе. . .
|
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод
Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод.
Thinkpad X220 Tablet —. . .
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|