|
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Дизайн и эволюция: перегрузка макросов10.02.2016, 04:10. Показов 8938. Ответов 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
Дизайн выпадающего меню под дизайн обычного Эволюция Эволюция растений Эволюция и человек
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
|
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма).
На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
|
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ *
Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам
Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
|
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым.
Но восстановить их можно так.
Для этого понадобится консольная утилита. . .
|
|
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
|
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11
— это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
|
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11
Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
|
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
|