| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Помогите написать пару макросов |
| Автор: newbee 3.2.2012, 16:02 | ||||
| Здравствуйте, мои дорогие плюсисты Как известно, операторы AND и OR возвращают boolean. Но это совершенно не вяжется с моим чувством прекрасного! Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления. Аналогично с OR: последовательно вычисляются выражения и возвращается результат первого истинного. Естественно OR и AND должны быть ленивыми. Надеюсь, всем здесь присутствующим очевидно, что AND и OR, если отбросить синтаксическую шелуху, являются разновидностью условного оператора, к примеру
В С++ условный оператор if-then-else не возвращает значения, зато есть ?: который подходит с существенным ограничением: типы всех выражений должны совпадать или быть приводимыми. Вторая проблема, с которой я столкнулась, - это рекурсивные макросы, которых в С++ нет, но с помощью внешнего генератора можно эмулировать. И вот я сейчас сижу и думаю как написать правильный AND-OR. Идеально синтаксически и семантически это должно выглядеть примерно так:
Интересно, возможно ли реализовать такое и насколько близко к тому, что я хочу... Макросы, шаблоны, неоптимало и тормозно - все пофигу, лишь бы заработало. Есть ли у кого какие соображения? |
| Автор: newbee 3.2.2012, 16:29 | ||||
Давай другой... Пусть у нас будут объекты типа object_t, они составляют иерархическую структуру (есть родители и дети) и все они где-нибудь зарегистрированы...
Можно. А если это потом можно будет повторить без него (сделать примитивные аналоги), вообще счастье будет Я на концерт убегаю, вечером вернусь! )) |
| Автор: boostcoder 3.2.2012, 16:31 |
оторвись, как следует. |
| Автор: newbee 3.2.2012, 16:33 | ||||
ЗЫЫЫ Сорри за плохой пример в ОП, постаралась нормальный придумать )) |
| Автор: boostcoder 3.2.2012, 16:34 |
| ага. понял. над решением нужно подумать... |
| Автор: newbee 3.2.2012, 16:35 |
| И наверное я погорячилась, с "hello" и false, давай считать, что внутри результаты выражений однотипны. Как в последнем примере. |
| Автор: tzirechnoy 3.2.2012, 17:25 |
| Шли бы Вы хаскель изучать, а? Тем более, что через монады это действительно делается, в том числе и в плюсах. |
| Автор: boostcoder 3.2.2012, 18:09 |
ок. сегодня постараюсь закончить.. реализация на boost.preprocessor. |
| Автор: borisbn 3.2.2012, 18:26 | ||||
| А что должен возвращать AND, если одно из выражений ложно ? В случае с bool или с указателем - понятно (false и NULL соответственно), а что в случае с int или с пользовательским типом ?
М.б. то выражение, на котором "споткнулся" ??? В данном случае o2 ? А как быть, если все выражения в OR - ложны ?
В общем, надо бы ТЗ поточнее выдать ))) |
| Автор: boostcoder 3.2.2012, 18:29 |
я так понял - исключение выбрасывать. |
| Автор: 502 3.2.2012, 18:34 | ||||
это все есть в javascript
|
| Автор: borisbn 3.2.2012, 18:38 | ||
дык
это ж не простой AND и OR... переменные в javascript не типизированны, а в Си++ ты не можешь в зависимости от условия присвоить переменной либо false либо std::string, например. |
| Автор: math64 3.2.2012, 18:40 | ||
Примерно так:
|
| Автор: 502 3.2.2012, 18:40 |
я поторопился, не false вроде в c++ есть auto, или нет? |
| Автор: borisbn 3.2.2012, 18:52 | ||
если на этапе компиляции тип возвращаемого значения у выражения понятен компилятору, то он вместо auto подставляет этот тип. если же компилятор не может определить тип (а в твоём случае он определяется на этапе выполнения), то компилятор выдаст ошибку на auto.
|
| Автор: boostcoder 3.2.2012, 19:13 | ||||
а если ни одно не истинно, что возвращать?
тут должен возвращаться результат второго, если первое не истинно? а если ни одно не истинно, бросать исключение? в первом случае так же? |
| Автор: boostcoder 3.2.2012, 21:01 | ||||
вот что получилось:
http://liveworkspace.org/code/f72ac6a3004d2b6b860bd21374ab273d результат препроцессирования:
т.к. не известно как поступать если ни одно из условий не верно, в макросы Ext_OR и Ext_AND добавил второй аргумент принимающий выражение. |
| Автор: newbee 3.2.2012, 23:50 | ||||||||
Ну это же прекрасно!
Сейчас не в состоянии распарсить, утром попробую ) Конструктор по умолчанию. Спасибо, сейчас попытаюсь сконцентрироваться. Вариант с def тоже уместен. |
| Автор: mes 4.2.2012, 00:12 |
| newbee, вот еще направление, если я прально понял задачу : http://liveworkspace.org/code/962529beac6cdf37e37a1ada28038e6e |
| Автор: newbee 4.2.2012, 00:15 | ||
Ууууух это вообще взрыв мозга))) Как это работает вообще не понятно)
AND как-то неправильно раскрывается... Добавлено через 9 минут и 53 секунды mes, спасибо большое, эта идея у меня была, но не придумала как побороть явное создание вспомогательных объектов... Все же подобная запись AND-OR интересна в первую очередь потому, что часто позволяет сильно сократить размер кода. Я обычно пользуюсь ленивостью || и && для записи условных выражений, но часто требуется получить значение выражения one || two || three, приходится писать лишний код... |
| Автор: boostcoder 4.2.2012, 00:30 | ||
что тут не так? Добавлено через 2 минуты и 8 секунд по отдельности Ext_OR и Ext_AND работают как надо? |
| Автор: newbee 4.2.2012, 00:36 |
| Я думаю, где-то скобок не хватает Смотри, у тебя AND работает по-разному для AND(1,0) и AND(0,1), хотя в обоих случаях должен быть false (или значение по умолчанию, как сейчас сделано у тебя). Добавлено через 3 минуты и 59 секунд http://liveworkspace.org/code/972cca9cb2abcaaf074fa566a52388b9 |
| Автор: boostcoder 4.2.2012, 00:41 | ||
нее ,компилятор бы ругался.
что-то накосячил... ща |
| Автор: newbee 4.2.2012, 00:43 |
| ЗЫ. Прикольный ты себе домен выбрал, уже скольок раз вижу, а кажется lispworks.com )) ЗЫЫ Модераторы, пожалуйста исправьте заголовок: "помогитЕ", я когда вижу эту ошибку, хочу убить автора. |
| Автор: boostcoder 4.2.2012, 00:44 | ||
это ты сама можешь сделать. "редактировать" на топике. Добавлено через 2 минуты и 35 секунд
ты тут не ошиблась? а то я сделал так, что возвращает результат последнего истинного выражения) |
| Автор: newbee 4.2.2012, 00:48 | ||
| Заголовок не дает исправить, только текст... Добавлено @ 00:50
Понимаешь, это тот же оператор AND по сути, только в случае успешной проверки (AND 1 2 3), возвращаем 3 вместо true, в случае неудачной (AND 1 0 2), возвращаем 0. |
| Автор: boostcoder 4.2.2012, 01:17 | ||||
вот:
http://liveworkspace.org/code/f35d3794bc73935d3ff02fba37c68e15 препроцессированный код:
все правильно? |
| Автор: mes 4.2.2012, 01:22 |
| boostcoder, если я правильно понял, то OR возвращает первое истинное, либо последнее если такого нет.. AND возвращает первое ложное, либо последнее если такого нет.. def не нужен |
| Автор: boostcoder 4.2.2012, 01:29 | ||
ну вроде как да... Добавлено @ 01:35 все равно не понимаю.. если не будет def, то что вернуть в случае лжи в следующем примере?
|
| Автор: mes 4.2.2012, 01:43 | ||
| newbee, логика работы операторв верна ? : http://liveworkspace.org/code/6ca83134283144feef7cb826178a2406 Добавлено через 2 минуты и 19 секунд
первый ложный |
| Автор: boostcoder 4.2.2012, 01:53 | ||||
судя по примеру в топике, предполагается в качестве выражений использовать и функции/методы. тогда записывать тернарное выражение нужно так?:
|
| Автор: mes 4.2.2012, 02:00 | ||
так для начала то хотелось бы с логикой разобраться, а уж потом думать в каком виде она нужна)) |
| Автор: boostcoder 4.2.2012, 02:01 |
ааа, понял |
| Автор: mes 4.2.2012, 02:02 | ||
полагаю что так :
|
| Автор: boostcoder 4.2.2012, 02:06 |
но b3 вообще не проверяется. Добавлено через 1 минуту и 8 секунд хотя из примера так и выходит... |
| Автор: mes 4.2.2012, 02:08 |
а зачем ? если оно ложно значит вернется ложь, если верное, то вернется правда) |
| Автор: boostcoder 4.2.2012, 02:10 | ||
| а для OR в случае лжи во всех выражения, что возвращать? моцг уже спать просится.. Добавлено через 28 секунд да-да. Добавлено через 8 минут и 33 секунды в общем, этот код правильный?
|
| Автор: mes 4.2.2012, 02:19 | ||
т.е. таже самая, тернарная конструкция, но без ! Добавлено через 1 минуту и 13 секунд в моем понимании вопроса да |
| Автор: boostcoder 4.2.2012, 02:26 | ||||
в моем тоже
http://liveworkspace.org/code/3fee4b8abd6a3bce91412183b759e6ec вывод:
ожидания ТС подтверждаются. |
| Автор: volatile 4.2.2012, 02:57 |
| Вопрос к даме. Это кальку с какого языка вы пытаетесь реализовать на С++? что-то имхо очень скриптовое... (и конечно не типизированное) |
| Автор: borisbn 4.2.2012, 09:49 |
| Автор: math64 5.2.2012, 00:29 | ||
| как-то не очень удобно в использовании получается Вот мой вариант:
OR работает так, как надо. AND при истинности возвращает последний элемент, а не первый. |
| Автор: mes 5.2.2012, 00:55 |
при истинности последний и должен ) |
| Автор: boostcoder 5.2.2012, 02:53 |
| math64, еще бы от Saver`а избавиться... |
| Автор: newbee 5.2.2012, 22:23 | ||
| Мммм и еще раз здравствуйте Друзья, из вашего сумбурного диалога я так и не поняла, поняли ли вы меня... Еще раз: функции OR и AND - не какие-то сферические штуковины со знакомыми названиями! Это аналогия обычных операторов && и ||, которые могут принимать >=0 параметров (на практике сойдет >=2). Как работает обычный ||: он последовательно вычисляет аргументы и как как только наткнется на истинный результат, возвращает true, OR же вместо true возвращает само это вычисленное значение. Если все аргументы ложны, и ||, и OR возвращают 0. Обычный &&: последовательно вычисляются аргументы, при встрече первого ложного результата возвращается 0, в AND - аналогично. Если результат вычисления всех аргументов истинен, && возвращает true, AND возвращает последний результат. mes, у тебя функции неленивые (поправь, если я не права), для AND/OR это недопустимо... В лучшем случае это обернется легко обнаруживаемым сегфолтом, в худшем - сложно уловимыми побочными эффектами. По логике правильно. volatile, Common Lisp. Не скриптовое, динамически типизированное. math64, спасибо за помощь, сейчас буду разбираться... boostcoder, тебе вообще огромное спасибо, сейчас тоже потыкаю твой последний вариант... Я вот сижу смотрю на раскрытие макроса и понимаю, что его аргументы (b1)(b2)(b3) будут вычисляться далеко не один раз... Значит нужно вначале раскрытия генерировать примерно следующее:
И потом внутри мега ?:-конструкции использовать __tmp_X вместо bX. Мне сложно судить наверняка, но при нынешнем однопроходном раскрытии макроса это нереально. И отчасти вдогонку к этому, не мог бы ты объяснить без привязки к BOOST_PP, каким образом препроцессор си раскрывает макрос macro((b1)(b2))? То есть получается, он не просто разбивает входные аргументы, а распарсивает выражение... |
| Автор: boostcoder 5.2.2012, 22:45 | ||
и выражения перестанут быть ленивыми. ты это.. протесть то что у меня получилось, чтоб я убедился в том что правильно тебя понял и сделал. потом подумаем над доделками. в терминах boost.preprocessor - это последовательность. я же, итерируюсь по последовательности, и на каждой итерации раскрываю часть общего выражения. Добавлено через 10 минут и 1 секунду можно дважды пройтись по последовательности. |
| Автор: volatile 5.2.2012, 23:56 |
Ну да. динамически типизированное. там это имеет практический смысл. В С++ даже если и получиться написать (кстати неплохие варианты тут предлагали, ребята постарались!) но использовать это почти не получится. Все аргументы должны быть приводимы к одному типу, и кроме того еще и к bool (если я правильно понял..) Где это можно использовать? Не, ну можно конечно что-то придумать такое, где такое применить, но это имхо, искусственное притягивание за уши. На приктике (при статической типизации) это практически бемполезная конструкция, имхо конечно. |
| Автор: newbee 6.2.2012, 08:44 | ||||
boostcoder, я поэксперементировала с твоими вариантами, с точки зрения логики раскрытия все правильно! Ты прав, сразу раскрывать все аргументы нельзя - привет, ленивость! Но нашлась мысля
А на моей практике это очень нужная конструкция. Мы с тобой просто программируем по-разному, которая экономит много строк кода. Где-то на первой странице я приводила немного надуманый, но наглядный пример. |
| Автор: boostcoder 6.2.2012, 09:34 | ||
не знал. попробую.
именно так. к примеру простой макрос BOOST_PP_SEQ_SIZE(): https://github.com/ryppl/boost-svn/blob/master/boost/preprocessor/seq/size.hpp макрос: var = BOOST_PP_SEQ_SIZE((a)(b)©) развернется в: var = BOOST_PP_SEQ_SIZE_BOOST_PP_SEQ_SIZE_3 который в свою очередь описан как: # define BOOST_PP_SEQ_SIZE_BOOST_PP_SEQ_SIZE_3 3 т.е. весь boost.preprocessor работает по нескольким основным принципам. либо по кол-ву аргументов, либо специализациями для всех возможных количеств аргументов. все на самом деле очень просто. Добавлено через 3 минуты и 58 секунд или я не понял вопроса... Добавлено через 8 минут и 57 секунд хм.. http://liveworkspace.org/code/35bcbcc90f05a2d8bd71d9b551f41499 дай ссылку на описание расширения. |
| Автор: newbee 6.2.2012, 09:53 |
| У тебя включен pedantic. http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Компилируй с -std=gnu++98 или -std=gnu++0x |
| Автор: boostcoder 6.2.2012, 10:04 |
угу. в общем работает. попробую доделать.. Добавлено через 2 минуты и 31 секунду mes, а Вы свой вариант будите доделывать? просто любопытно посмотреть на решение. я тут еще подумал... для функционального программирования в с++, разработали http://www.boost.org/doc/libs/1_48_0/libs/phoenix/index.html. еще попробую с его помощью решить задачу. |
| Автор: mes 6.2.2012, 10:13 |
| boostcoder, мой вариант придет к буст лямбде еще не приходилось сталкиваться |
| Автор: boostcoder 6.2.2012, 10:14 |
| Автор: boostcoder 9.2.2012, 01:28 | ||||||
| newbee, итак. давай посмотрим на препроцессированный вариант твоих тестов:
результат:
теперь нужно выявить вложенность "скопов" для того чтоб определить в каком скопе какое выражение должно вычисляться... Добавлено @ 01:32 лишние скобки уберем.. Добавлено @ 01:36 вот что получилось:
|
| Автор: newbee 9.2.2012, 11:03 | ||||||
boostcoder, у тебя сложно раскрывается AND. Я для наглядности буду возвращать нули вместо самих вычисленных значений.
Теперь... Смотри, внутри OR и AND излишне следовать правилу раскрытия элемента последовательности x?x: Если x - вложенный AND или OR, его можно прямо встроить в выражение. Я не знаю, можно ли это сделать на дефайнах... Это необязательно. Таким образом твой пример принял бы форму
Теперь давай подумаем со скопами...
И аналогично должно быть с OR. Потом напишу, если надо. Я нигде не накосячила? |
| Автор: boostcoder 9.2.2012, 13:19 |
| вроде въехал.. по моему - нет. |
| Автор: math64 10.2.2012, 09:33 | ||
(не проверял) |
| Автор: boostcoder 10.2.2012, 10:20 | ||
| newbee, смотри какое дело. код:
как ты можешь видеть, тут вложенные скопы. но препроцессор не может рекурсию. он однопроходный. идеи? |
| Автор: boostcoder 10.2.2012, 10:53 | ||
| попробовал двумя проходами по последовательности генерировать сначала открывающиеся скопы, потом по той же последовательности, закрывающиеся. на примере Ext_OR((b1)(b2)(b3)):
вроде то, что надо. но при попытке использовать вложенные макросы "Ext_OR ((b1)(b2)(b3)(Ext_OR ((b1)(b2)(b3))))" получаю ошибку препроцессора. и правильно. при первом проходе еще ничего не сгенеренно. по этому препроцессор генерит нормально, не смотря на непарные скобки. но при втором проходе, он, "видя" такое ( идеи будут? Добавлено через 2 минуты и 6 секунд math64, не правильно. в твоем коде все равно выражения будут вычисляться не единожды. |
| Автор: newbee 10.2.2012, 12:57 | ||||
| Бустик, я совсем запуталась в твоих буст-пппроблемах :( Сделала OR сама, ленивый, молодежный, современный!
Критика, вопросы, предложения приветствуются! PS. В архиве несколько вспомогательных файлов. |
| Автор: k0rvin 10.2.2012, 13:31 | ||
Жду решения на Хаскелле. |
| Автор: boostcoder 10.2.2012, 13:35 | ||
| слуш. а что если макрос будет раскрываться так?
т.е. все выражения будут вычисляться сразу. а? или не актуально? Добавлено через 2 минуты и 33 секунды а в архиве какие конкретно вирусы? Добавлено через 5 минут и 48 секунд вообще у тебя не плохо получилось. и без зависимости от буста |
| Автор: newbee 10.2.2012, 13:43 | ||
Но сначала вычислять никак нельзя. Посмотри любой свой код, с нелинивыми операторами if, || и && он скорее всего рассыпется. Добавлено через 2 минуты и 48 секунд Он несжатый) Потому что нагенерировала специфичных под задачу макросов? Хотела сделать более обобщенный FOREACH, но там были бы сложности и неудобства. Или что еще плохо? |
| Автор: boostcoder 10.2.2012, 13:46 | ||
ну да.. Добавлено через 11 секунд ладно, думаю... |
| Автор: newbee 10.2.2012, 13:46 |
| Блин, косая я. Не плохо получилось)) Неплохо, да! )) |
| Автор: boostcoder 10.2.2012, 13:47 |
это не стёб был. в самом деле нормально получилось. просто и понятно. Добавлено через 26 секунд Добавлено через 14 минут и 49 секунд ну..мне простительно. русский мне не родной язык |
| Автор: math64 10.2.2012, 18:37 | ||||
| Вычислятся быдут один раз. Проверяться и копироваться - да, много раз (при сложной формуле). Идеи? Не пытаться делать макрос в переменным числом агрументов, генерирующих всё выражение, а набор макросов генерирующих фрагменты выражения. Временной для запоминания переменной можно обойтись одной, поэтому можно опробовать что-то типа
Возможно использовать набор макросов AND2(var1,var2), AND3(var1,var2,var3) и т.д. Добавлено через 5 минут и 50 секунд Неправильно. Выражения должны вычисляться только после проверки предыдущих:
|
| Автор: newbee 10.2.2012, 19:13 |
| math64, я не понимаю, что у тебя за бегины и енды... Ты что-то недокопипастил?.. Добавлено через 10 минут и 41 секунду Кстати... Есть ли у кого-нибудь идеи, как избавиться от typeof и ({}) расширений? На шаблонах или хз как еще... Возможно придется компилировать под винду, там я предпочитаю компилятор MSVC. |
| Автор: vol4ek 10.2.2012, 19:33 | ||
на VB похоже... |
| Автор: math64 10.2.2012, 19:52 | ||
Отвечал на последнее сообщение предыдущей страницы - не заметил что есть ещё сообщения. Это просто идеи, как построить макросы - не проработано до конца. Если типы всех переменных одинаковы, можно использовать только одну временную переменную, которая объявлена в макросе BEGIN(type) Макрос END закрывает объявление Макросы, используемые в середине не проработаны. Идея c AND2(), AND3(), OR2(), OR3() - уже не актуальна, Вы сделали лучше. Как избавиться от ({}) - я уже предлагал - класс Saver, его можно переделать, чтобы был синглетоном и замоминал всё что можно как Variant, но typeof() всё равно нужен, чтобы получить запомненное значение нужного типа. Но если комплятор поддерживает ({}) - лучше использовать их (в объявлении макросов - условная трансляция) |
| Автор: boostcoder 10.2.2012, 20:05 | ||
не нужно повторять.
жуть какая-то) как же такое юзать? оО а если нет? |
| Автор: math64 10.2.2012, 21:14 | ||||||
уже объяснял - не прочитал всё до конца если нет - x ? y : z всё равно не скомпилируется, или все должны приводиться к типу первого выражения, его и использовать, или объявить тип переменной самостоятельно.
В этом случае тип результата нужно объявлять самостоятельно
Правда, есть случай, когда даже при одном типе объединять нельзя:
Но он тоже не компилируется - результат ({ }) не int&, а int |
| Автор: boostcoder 10.2.2012, 21:25 |
да. туплю. |
| Автор: math64 11.2.2012, 08:46 | ||
| Нужно доработать макросы AND и OR, чтобы принимали переменное число агрументов (как в PP_NARG.h или из boost) и моглм комбинироваться. TEST используется для задания значения по умолчанию для обычных типов TESTR используется для задания значения по умолчанию для ссылок для ссылок желательно обезопасить от порчи значение по умочанию.
|