Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Помогите написать пару макросов


Автор: newbee 3.2.2012, 16:02
Здравствуйте, мои дорогие плюсисты smile

Как известно, операторы AND и OR возвращают boolean. Но это совершенно не вяжется с моим чувством прекрасного! Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления. Аналогично с OR: последовательно вычисляются выражения и возвращается результат первого истинного. Естественно OR и AND должны быть ленивыми.

Надеюсь, всем здесь присутствующим очевидно, что AND и OR, если отбросить синтаксическую шелуху, являются разновидностью условного оператора, к примеру
Код

one AND two AND three ->
if(one)
 if(two)
  if(three)


В С++ условный оператор if-then-else не возвращает значения, зато есть ?: который подходит с существенным ограничением: типы всех выражений должны совпадать или быть приводимыми.

Вторая проблема, с которой я столкнулась, - это рекурсивные макросы, которых в С++ нет, но с помощью внешнего генератора можно эмулировать.

И вот я сейчас сижу и думаю как написать правильный AND-OR. Идеально синтаксически и семантически это должно выглядеть примерно так:
Код

std::cout<<$AND(myobject, 2, 3-5, string.indexOf('q')!=42, "hello")<<std::endl; => "hello"(pass) | false (fail)
object *o=$AND(object_registered(another)) => another | nil
//object_registered(another) => another | nil
object *o=$(OR object1 object2 object3) => first of non-nil object | nil


Интересно, возможно ли реализовать такое и насколько близко к тому, что я хочу... Макросы, шаблоны, неоптимало и тормозно - все пофигу, лишь бы заработало. Есть ли у кого какие соображения?

Автор: boostcoder 3.2.2012, 16:12
newbee, жуткий пример %)
ты таки на лиспе пишешь?
покажи псевдокодом что хочешь получить в итоге?

зы
boost можно использовать?

Добавлено через 5 минут
Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
one AND two AND three ->
if(one)
 if(two)
  if(three)

это понятно. не понял что должно (хочешь) получить в итоге.

Добавлено через 7 минут и 29 секунд
Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
std::cout<<$AND(myobject, 2, 3-5, string.indexOf('q')!=42, "hello")<<std::endl; => "hello"(pass) | false (fail)

это расшифруй.

Добавлено через 11 минут и 2 секунды
Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
=> "hello"(pass) | false (fail)

т.е. результатом того что выше, может быть либо "hello(pass)", либо "false (fail)" ? но опять же, не понятно назначение и способ вычисления переменных в $AND(...)

Добавлено через 14 минут и 21 секунду
Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления. Аналогично с OR: последовательно вычисляются выражения и возвращается результат первого истинного. Естественно OR и AND должны быть ленивыми.

кажись понял.. но возвращаться же будет bool, а в твоем примере "hello" %)

Автор: newbee 3.2.2012, 16:29
Код
покажи псевдокодом что хочешь получить в итоге?
Ну я выше уже пыталась))

Давай другой... Пусть у нас будут объекты типа object_t, они составляют иерархическую структуру (есть родители и дети) и все они где-нибудь зарегистрированы...

Код

object_t *o1, *o2;
...
object_t *res=$OR(o1, find_object("Object"), $AND(o2, o2->parent()), make_default_object());

//Это выражение читается так:
object_t *res=0;
if(o1)
 res=o1;
 else{
  if(object_t *tmp=find_object("Object"))
   res=tmp;
   else{
    if(o2 && o2->parent()!=0)
     res=o2->parent();
     else{
      res=make_default_object();
     }
   }
 }


Цитата(boostcoder @  3.2.2012,  17:12 Найти цитируемый пост)

зы
boost можно использовать? 
Можно. А если это потом можно будет повторить без него (сделать примитивные аналоги), вообще счастье будет smile

Я на концерт убегаю, вечером вернусь! ))

Автор: boostcoder 3.2.2012, 16:31
Цитата(newbee @  3.2.2012,  16:29 Найти цитируемый пост)
Я на концерт убегаю

 smile 
оторвись, как следует.

Автор: newbee 3.2.2012, 16:33
Цитата(boostcoder @  3.2.2012,  17:12 Найти цитируемый пост)
результатом того что выше, может быть либо "hello(pass)", либо "false (fail)"
В случае успеха - "hello", в случае неудачи - false.

Цитата(boostcoder @  3.2.2012,  17:12 Найти цитируемый пост)
кажись понял.. но возвращаться же будет bool, а в твоем примере "hello" %) 
 ?: возвращает сам объект. Но там тоже с ограничением по типам, я выше писала.

ЗЫЫЫ Сорри за плохой пример в ОП, постаралась нормальный придумать ))

Автор: 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
Цитата(newbee @  3.2.2012,  16:35 Найти цитируемый пост)
давай считать, что внутри результаты выражений однотипны. 

ок.

сегодня постараюсь закончить.. реализация на boost.preprocessor.

Автор: borisbn 3.2.2012, 18:26
А что должен возвращать AND, если одно из выражений ложно ?
В случае с bool или с указателем - понятно (false и NULL соответственно), а что в случае с int или с пользовательским типом ?

Код

struct MyObject {
    MyObject( bool trueOrFalse ) : m_trueOrFalse;
    operator bool() const { return m_trueOrFalse; }
    bool m_trueOrFalse;
};
MyObject o1( true ), o2( false );
MyObject res = AND( o1, o2 );


М.б. то выражение, на котором "споткнулся" ??? В данном случае o2 ?

А как быть, если все выражения в OR - ложны ?
Код

MyObject o1( false ), o2( false );
MyObject res = OR( o1, o2 );


В общем, надо бы ТЗ поточнее выдать )))

Автор: boostcoder 3.2.2012, 18:29
Цитата(borisbn @  3.2.2012,  18:26 Найти цитируемый пост)
А что должен возвращать AND, если одно из выражений ложно ?


Цитата(borisbn @  3.2.2012,  18:26 Найти цитируемый пост)
А как быть, если все выражения в OR - ложны ?

я так понял - исключение выбрасывать.

Автор: 502 3.2.2012, 18:34
Цитата(borisbn @  3.2.2012,  18:26 Найти цитируемый пост)
А что должен возвращать AND, если одно из выражений ложно ?

Цитата(borisbn @  3.2.2012,  18:26 Найти цитируемый пост)
М.б. то выражение, на котором "споткнулся" ???

 smile 


Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления. Аналогично с OR: последовательно вычисляются выражения и возвращается результат первого истинного. Естественно OR и AND должны быть ленивыми.

это все есть в javascript
Код

(4 && 5) + 4 //=> 9
(5 && 4!=4) //=> false
(5 && 0) //=> 0

Автор: borisbn 3.2.2012, 18:38
Цитата(502 @  3.2.2012,  18:34 Найти цитируемый пост)
А что должен возвращать AND, если одно из выражений ложно ?

false

дык
Цитата(borisbn @  3.2.2012,  18:26 Найти цитируемый пост)
В случае с bool или с указателем - понятно (false и NULL соответственно), а что в случае с int или с пользовательским типом ?


это ж не простой AND и OR...

Цитата(502 @  3.2.2012,  18:34 Найти цитируемый пост)
это все есть в javascript

переменные в javascript не типизированны, а в Си++ ты не можешь в зависимости от условия присвоить переменной либо false либо std::string, например.

Автор: math64 3.2.2012, 18:40
Примерно так:
Код

// При необходимости прикрутить шаблоны
typedef void* T;
T temp_push(T);
T temp_pop();
#define AND(a,b) (temp_push(a)?temp_pop(),(b):(temp_pop(),))
#define OR(a,b) (temp_push(a)?temp_pop():(temp_pop(),(b)))


Автор: 502 3.2.2012, 18:40
Цитата(borisbn @  3.2.2012,  18:38 Найти цитируемый пост)
дык

я поторопился, не false
Цитата(borisbn @  3.2.2012,  18:38 Найти цитируемый пост)
переменные в javascript не типизированны

вроде в c++ есть auto, или нет?

Автор: borisbn 3.2.2012, 18:52
Цитата(502 @  3.2.2012,  18:40 Найти цитируемый пост)
вроде в c++ есть auto, или нет?

если на этапе компиляции тип возвращаемого значения у выражения понятен компилятору, то он вместо auto подставляет этот тип. если же компилятор не может определить тип (а в твоём случае он определяется на этапе выполнения), то компилятор выдаст ошибку на auto.
Код

std::vector< int > v;
auto it = v.begin(); // тип it будет std::vector< int >::iterator

std::string str = "true";
bool b = false;
auto x = ... ? str : b; // error

Автор: boostcoder 3.2.2012, 19:13
Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления.

а если ни одно не истинно, что возвращать?

Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
OR: последовательно вычисляются выражения и возвращается результат первого истинного.

тут должен возвращаться результат второго, если первое не истинно? а если ни одно не истинно, бросать исключение? в первом случае так же?

Автор: boostcoder 3.2.2012, 21:01
вот что получилось:
Код

#include <iostream>
#include <boost/preprocessor.hpp>

#define Ext_OR_SUBCOND(unused, idx, seq) \
   (BOOST_PP_SEQ_ELEM(idx, seq)) \
   ? \
   (BOOST_PP_SEQ_ELEM(idx, seq)) \
   :

#define Ext_OR(seq, def) \
   ( \
      BOOST_PP_REPEAT( \
         BOOST_PP_SEQ_SIZE(seq), \
         Ext_OR_SUBCOND, \
         seq \
      ) \
      (def) \
   )

#define Ext_AND_SUBCOND(unused, idx, tuple) \
   !( \
      BOOST_PP_SEQ_ELEM( \
         idx, \
         BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
      ) \
   ) ? ( \
      BOOST_PP_IF( \
         BOOST_PP_EQUAL(idx, 0), \
         BOOST_PP_TUPLE_ELEM(2, 1, tuple), \
         BOOST_PP_SEQ_ELEM( \
            BOOST_PP_SUB(idx, 1), \
            BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
         ) \
      ) \
   ) :

#define Ext_AND(seq, def) \
   ( \
      BOOST_PP_REPEAT( \
         BOOST_PP_SEQ_SIZE(seq), \
         Ext_AND_SUBCOND, \
         (seq,def) \
      ) \
      ( \
         BOOST_PP_SEQ_ELEM( \
            BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), \
            seq \
         ) \
      ) \
   )

int def() {
   return -1;
}

int main() {
   int b1=1, b2=2, b3=3;

   std::cout << Ext_OR((b1)(b2)(b3), def()) << std::endl; // 1
   std::cout << Ext_AND((b1)(b2)(b3), def()) << std::endl; // 3
}

http://liveworkspace.org/code/f72ac6a3004d2b6b860bd21374ab273d

результат препроцессирования:
Код

int def() {
   return -1;
}

int main() {
   int b1=1, b2=2, b3=3, b4=0;

   std::cout << ( ( b1 ) ? ( b1 ) : ( b2 ) ? ( b2 ) : ( b3 ) ? ( b3 ) : (def()) ) << std::endl;
   std::cout << ( !( b1 ) ? ( def() ) : !( b2 ) ? ( b1 ) : !( b3 ) ? ( b2 ) : ( b3 ) ) << std::endl;
}



т.к. не известно как поступать если ни одно из условий не верно, в макросы Ext_OR и Ext_AND добавил второй аргумент принимающий выражение.

Автор: newbee 3.2.2012, 23:50
Цитата(borisbn @  3.2.2012,  19:26 Найти цитируемый пост)
А что должен возвращать AND, если одно из выражений ложно ?
В случае с bool или с указателем - понятно (false и NULL соответственно), а что в случае с int или с пользовательским типом ?
Конструктор по умолчанию.

Цитата(tzirechnoy @  3.2.2012,  18:25 Найти цитируемый пост)
Шли бы Вы хаскель изучать, а? Тем более, что через монады это действительно делается, в том числе и в плюсах. 
Ну вот зачем ты глупую девушку грузишь такими высокими материями, монады, каррирование, паттерн матчинг... Может мне еще матфаковский курс матана вызубрить и теорию категорий? Если напишешь свой вариант с монадами и замыканиями или дашь ссылки на решение моей задачки, будем разговаривать...

Цитата(borisbn @  3.2.2012,  19:26 Найти цитируемый пост)
М.б. то выражение, на котором "споткнулся" ??? В данном случае o2 ?
Нет же, суть AND в том, чтобы сигнализировать о фэйле через возвращаемое значение. В топку пользовательские типы, хотя бы для целых и указателей...

Цитата(502 @  3.2.2012,  19:34 Найти цитируемый пост)
это все есть в javascript
Ну это же прекрасно!

Цитата(borisbn @  3.2.2012,  19:38 Найти цитируемый пост)
переменные в javascript не типизированны, а в Си++ ты не можешь в зависимости от условия присвоить переменной либо false либо std::string, например. 
Вот-вот. Статическую типизацию можно частично забороть шаблонами (ну то есть как бы забороть, она останется в силе) или накрутить ручную динамическую... Я конечно больше за второй вариант, но он сливает в производительности, поэтому в С++ от статической лучше не отказываться.

Цитата(math64 @  3.2.2012,  19:40 Найти цитируемый пост)
Примерно так:
Сейчас не в состоянии распарсить, утром попробую )

Цитата(boostcoder @  3.2.2012,  20:13 Найти цитируемый пост)
а если ни одно не истинно, что возвращать?
Конструктор по умолчанию.

Цитата(boostcoder @  3.2.2012,  22:01 Найти цитируемый пост)
вот что получилось:
Спасибо, сейчас попытаюсь сконцентрироваться. Вариант с def тоже уместен.


Автор: mes 4.2.2012, 00:12
newbee, 
вот еще направление, если я прально понял задачу :
http://liveworkspace.org/code/962529beac6cdf37e37a1ada28038e6e

Автор: newbee 4.2.2012, 00:15
Ууууух это вообще взрыв мозга))) Как это работает вообще не понятно)

Код

std::cout << Ext_OR((0)(Ext_AND((1)(0), 0))(2), def()) << std::endl; //wait: 2; recieve: 1 : FAIL
std::cout << Ext_OR((0)(Ext_AND((0)(1), 0))(2), def()) << std::endl; //wait: 2; recieve: 2 : OK


AND как-то неправильно раскрывается...

Добавлено через 9 минут и 53 секунды
mes, спасибо большое, эта идея у меня была, но не придумала как побороть явное создание вспомогательных объектов... Все же подобная запись AND-OR интересна в первую очередь потому, что часто позволяет сильно сократить размер кода.

Я обычно пользуюсь ленивостью || и && для записи условных выражений, но часто требуется получить значение выражения one || two || three, приходится писать лишний код... 

Автор: boostcoder 4.2.2012, 00:30
Код

int main() {
   std::cout << ( (0) ? (0) : (( !( 1 ) ? ( 0 ) : !( 0 ) ? ( 1 ) : ( 0 ) )) ? (( !( 1 ) ? ( 0 ) : !( 0 ) ? ( 1 ) : ( 0 ) )) : (2) ? (2) : (def()) ) << std::endl;
   std::cout << ( (0) ? (0) : (( !( 0 ) ? ( 0 ) : !( 1 ) ? ( 0 ) : ( 1 ) )) ? (( !( 0 ) ? ( 0 ) : !( 1 ) ? ( 0 ) : ( 1 ) )) : (2) ? (2) : (def()) ) << std::endl;
}


что тут не так? smile

Добавлено через 2 минуты и 8 секунд
по отдельности Ext_OR и Ext_AND работают как надо?

Автор: newbee 4.2.2012, 00:36
Цитата(boostcoder @  4.2.2012,  01:30 Найти цитируемый пост)
что тут не так?
Я думаю, где-то скобок не хватает  smile 

Смотри, у тебя 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:36 Найти цитируемый пост)
где-то скобок не хватает

нее ,компилятор бы ругался.

Цитата(newbee @  4.2.2012,  00:36 Найти цитируемый пост)
у тебя AND работает по-разному для AND(1,0) и AND(0,1), хотя в обоих случаях должен быть false (или значение по умолчанию, как сейчас сделано у тебя).

что-то накосячил... ща

Автор: newbee 4.2.2012, 00:43
ЗЫ. Прикольный ты себе домен выбрал, уже скольок раз вижу, а кажется lispworks.com ))

ЗЫЫ Модераторы, пожалуйста исправьте заголовок: "помогитЕ", я когда вижу эту ошибку, хочу убить автора.

Автор: boostcoder 4.2.2012, 00:44
Цитата(newbee @  4.2.2012,  00:43 Найти цитируемый пост)
ЗЫЫ Модераторы, пожалуйста исправьте заголовок

это ты сама можешь сделать. "редактировать" на топике.

Добавлено через 2 минуты и 35 секунд
Цитата(newbee @  3.2.2012,  16:02 Найти цитируемый пост)
Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления.

ты тут не ошиблась?

а то я сделал так, что возвращает результат последнего истинного выражения)

Автор: newbee 4.2.2012, 00:48
Заголовок не дает исправить, только текст...

Добавлено @ 00:50
Цитата(boostcoder @  4.2.2012,  01:44 Найти цитируемый пост)
ты тут не ошиблась?

Цитата(boostcoder @  4.2.2012,  01:44 Найти цитируемый пост)
Правильный AND (или цепочка из них) должен последовательно выполнять выражения и в случае истинности их всех возвращать результат последнего вычисления.


Понимаешь, это тот же оператор AND по сути, только в случае успешной проверки (AND 1 2 3), возвращаем 3 вместо true, в случае неудачной (AND 1 0 2), возвращаем 0.

Автор: boostcoder 4.2.2012, 01:17
вот:
Код

#include <iostream>
#include <boost/preprocessor.hpp>

#define Ext_OR_SUBCOND(unused, idx, seq) \
   (BOOST_PP_SEQ_ELEM(idx, seq)) \
   ? \
   (BOOST_PP_SEQ_ELEM(idx, seq)) \
   :

#define Ext_OR(seq, def) \
   ( \
      BOOST_PP_REPEAT( \
         BOOST_PP_SEQ_SIZE(seq), \
         Ext_OR_SUBCOND, \
         seq \
      ) \
      (def) \
   )


#define Ext_AND_SUBCOND(unused, idx, tuple) \
   ( \
      BOOST_PP_SEQ_ELEM( \
         idx, \
         BOOST_PP_TUPLE_ELEM(2, 0, tuple) \
      ) \
   ) \
   BOOST_PP_IF( \
      BOOST_PP_NOT_EQUAL( \
         BOOST_PP_ADD(idx, 1), \
         BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(2, 0, tuple)) \
      ), \
      && , \
      \
   )
   

#define Ext_AND(seq, def) \
   ( \
      ( \
         BOOST_PP_REPEAT( \
            BOOST_PP_SEQ_SIZE(seq), \
            Ext_AND_SUBCOND, \
            (seq,def) \
         ) \
      ) \
      ? \
      ( \
         BOOST_PP_SEQ_ELEM( \
            BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), \
            seq \
         ) \
      ) \
      : (def) \
   )

int def() {
   return -1;
}

int main() {
   std::cout << Ext_OR((0)(Ext_AND((1)(0), 0))(2), def()) << std::endl; //wait: 2; recieve: 1 : FAIL
   std::cout << Ext_OR((0)(Ext_AND((0)(1), 0))(2), def()) << std::endl; //wait: 2; recieve: 2 : OK
}

http://liveworkspace.org/code/f35d3794bc73935d3ff02fba37c68e15

препроцессированный код:
Код

int main() {
   std::cout << ( (0) ? (0) : (( ( ( 1 ) && ( 0 ) ) ? ( 0 ) : (0) )) ? (( ( ( 1 ) && ( 0 ) ) ? ( 0 ) : (0) )) : (2) ? (2) : (def()) ) << std::endl;
   std::cout << ( (0) ? (0) : (( ( ( 0 ) && ( 1 ) ) ? ( 1 ) : (0) )) ? (( ( ( 0 ) && ( 1 ) ) ? ( 1 ) : (0) )) : (2) ? (2) : (def()) ) << std::endl;
}


все правильно?

Автор: mes 4.2.2012, 01:22
boostcoder, если я правильно понял, то 
OR возвращает первое истинное, либо последнее если такого нет..
AND возвращает первое ложное, либо последнее если такого нет..
def  не нужен

Автор: boostcoder 4.2.2012, 01:29
Цитата(mes @  4.2.2012,  01:22 Найти цитируемый пост)
def  не нужен 

ну вроде как да...

Добавлено @ 01:35
все равно не понимаю..
если не будет def, то что вернуть в случае лжи в следующем примере?
Код

( b1 ) && ( b2 ) && ( b3 ) ? ( b3 ) : def()

Автор: mes 4.2.2012, 01:43
newbee,  логика работы операторв верна ? :
http://liveworkspace.org/code/6ca83134283144feef7cb826178a2406

Добавлено через 2 минуты и 19 секунд
Цитата(boostcoder @  4.2.2012,  00:29 Найти цитируемый пост)
если не будет def, то что вернуть в случае лжи в следующем примере?

первый ложный smile

Автор: boostcoder 4.2.2012, 01:53
Цитата(mes @  4.2.2012,  01:43 Найти цитируемый пост)
newbee,  логика работы операторв верна ? :
http://liveworkspace.org/code/6ca831342831...f7cb826178a2406

судя по примеру в топике, предполагается в качестве выражений использовать и функции/методы.

Цитата(mes @  4.2.2012,  01:43 Найти цитируемый пост)
первый ложный

тогда записывать тернарное выражение нужно так?:
Код

!(b1)?(b1)
   :!(b2)?(b2)
      :!(b3)?(b3);

Автор: mes 4.2.2012, 02:00
Цитата(boostcoder @  4.2.2012,  00:53 Найти цитируемый пост)
судя по примеру в топике, предполагается в качестве выражений использовать и функции/методы.

так для начала то хотелось бы с логикой разобраться, а уж потом думать в каком виде она нужна))

Автор: boostcoder 4.2.2012, 02:01
Цитата(mes @  4.2.2012,  02:00 Найти цитируемый пост)
для начала то хотелось бы с логикой разобраться

ааа, понял smile

Автор: mes 4.2.2012, 02:02
Цитата(boostcoder @  4.2.2012,  00:53 Найти цитируемый пост)
тогда записывать тернарное выражение нужно так?:

полагаю что так :
Код

!(b1)?(b1)
   :!(b2)?(b2)
      :(b3);


Автор: boostcoder 4.2.2012, 02:06
Цитата(mes @  4.2.2012,  02:02 Найти цитируемый пост)
:(b3);

но b3 вообще не проверяется.

Добавлено через 1 минуту и 8 секунд
Цитата(newbee @  4.2.2012,  00:48 Найти цитируемый пост)
в случае успешной проверки (AND 1 2 3), возвращаем 3

хотя из примера так и выходит...

Автор: mes 4.2.2012, 02:08
Цитата(boostcoder @  4.2.2012,  01:06 Найти цитируемый пост)
но b3 вообще не проверяется. 


а зачем ? если оно ложно значит вернется ложь, если верное, то вернется правда)

Автор: boostcoder 4.2.2012, 02:10
а для OR в случае лжи во всех выражения, что возвращать?
моцг уже спать просится..

Добавлено через 28 секунд
Цитата(mes @  4.2.2012,  02:08 Найти цитируемый пост)
если оно ложно значит вернется ложь, если верное, то вернется правда

да-да.

Добавлено через 8 минут и 33 секунды
в общем, этот код правильный? smile 
Код

int main() {
   int b1=1, b2=2, b3=3;

   std::cout << ( (b1) ? (b1) : (b2) ? (b2) : ( b3 ) << std::endl;
   std::cout << ( !(b1) ? (b1) : !(b2) ? (b2) : ( b3 ) << std::endl;
}


Автор: mes 4.2.2012, 02:19
Цитата(boostcoder @  4.2.2012,  01:10 Найти цитируемый пост)
а для OR в случае лжи во всех выражения, что возвращать?


Цитата(mes @  4.2.2012,  00:22 Найти цитируемый пост)
OR возвращает первое истинное, либо последнее если такого нет..
AND возвращает первое ложное, либо последнее если такого нет..


т.е. таже самая, тернарная конструкция, но без !

Добавлено через 1 минуту и 13 секунд
Цитата(boostcoder @  4.2.2012,  01:10 Найти цитируемый пост)
в общем, этот код правильный?

в моем понимании вопроса да smile

Автор: boostcoder 4.2.2012, 02:26
Цитата(mes @  4.2.2012,  02:19 Найти цитируемый пост)
в моем понимании вопроса да

в моем тоже smile
Код

#include <iostream>
#include <boost/preprocessor.hpp>

#define Ext_OR_SUBCOND(unused, idx, seq) \
   (BOOST_PP_SEQ_ELEM(idx, seq)) \
   ? \
   (BOOST_PP_SEQ_ELEM(idx, seq)) :

#define Ext_OR(seq) \
   ( \
      BOOST_PP_REPEAT( \
         BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), \
         Ext_OR_SUBCOND, \
         seq \
      ) ( \
         BOOST_PP_SEQ_ELEM( \
            BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), \
            seq \
         ) \
      ) \
   )

#define Ext_AND_SUBCOND(unused, idx, seq) \
   !(BOOST_PP_SEQ_ELEM(idx, seq)) \
   ? \
   (BOOST_PP_SEQ_ELEM(idx, seq)) :

#define Ext_AND(seq) \
   ( \
      BOOST_PP_REPEAT( \
         BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), \
         Ext_AND_SUBCOND, \
         seq\
      ) ( \
         BOOST_PP_SEQ_ELEM( \
            BOOST_PP_SUB(BOOST_PP_SEQ_SIZE(seq), 1), \
            seq \
         ) \
      ) \
   )

int main() {
   int b1=1, b2=2, b3=3;

   std::cout << Ext_OR ((b1)(b2)(b3)) << std::endl; // 1
   std::cout << Ext_AND((b1)(b2)(b3)) << std::endl; // 3
   std::cout << Ext_OR((0)(Ext_AND((1)(0)))(2)) << std::endl; //wait: 2; recieve: 1 : FAIL
   std::cout << Ext_OR((0)(Ext_AND((0)(1)))(2)) << std::endl; //wait: 2; recieve: 2 : OK
}

http://liveworkspace.org/code/3fee4b8abd6a3bce91412183b759e6ec
вывод:
Цитата

1
3
2
2

ожидания ТС подтверждаются.

Автор: volatile 4.2.2012, 02:57
Вопрос к даме. Это кальку с какого языка вы пытаетесь реализовать на С++?
что-то имхо очень скриптовое... (и конечно не типизированное)

Автор: borisbn 4.2.2012, 09:49
Цитата(volatile @  4.2.2012,  02:57 Найти цитируемый пост)
Это кальку с какого языка вы пытаетесь реализовать на С++?

Цитата(boostcoder @  3.2.2012,  16:12 Найти цитируемый пост)
ты таки на лиспе пишешь?

Цитата(newbee @  4.2.2012,  00:43 Найти цитируемый пост)
а кажется lispworks

 smile 

Автор: math64 5.2.2012, 00:29
как-то не очень удобно в использовании получается
Цитата(boostcoder @  4.2.2012,  02:26 Найти цитируемый пост)
   std::cout << Ext_OR((0)(Ext_AND((1)(0)))(2)) << std::endl;

Вот мой вариант:
Код

template <typename T>
class Saver {
public:
  friend bool operator || (T t, Saver& saver) { saver.save = t; return !!t; }
  friend bool operator && (T t, Saver& saver) { saver.save = t; return !t; }
  T get() { return save; }
private:
  T save;
};

// a && b --> нужно a ? (b ? a : 0) : 0 или !a ? 0 : b ? a : 0 получается !a ? a : b
#define AND && saver ? saver.get() :
// a || b --> a ? a : b
#define OR || saver ? saver.get() :

int f() { return 0; }
int main()
{
Saver<int> saver;
int a = 1, b = 2, c = 0;
cout << (a OR b) << endl;
cout << (a OR c) << endl;
cout << (c OR b) << endl;
cout << (c OR a OR b) << endl;
cout << (c OR (a AND b)) << endl;
cout << (f() OR (a AND b)) << endl;
}

OR работает так, как надо.
AND при истинности возвращает последний элемент, а не первый.

Автор: mes 5.2.2012, 00:55
Цитата(math64 @  4.2.2012,  23:29 Найти цитируемый пост)
AND при истинности возвращает последний элемент, а не первый.

при истинности последний и должен )

Автор: boostcoder 5.2.2012, 02:53
math64, еще бы от Saver`а избавиться...

Автор: newbee 5.2.2012, 22:23
Мммм и еще раз здравствуйте smile

Друзья, из вашего сумбурного диалога я так и не поняла, поняли ли вы меня... Еще раз: функции OR и AND - не какие-то сферические штуковины со знакомыми названиями! Это аналогия обычных операторов && и ||, которые могут принимать  >=0 параметров (на практике сойдет >=2). Как работает обычный ||: он последовательно вычисляет аргументы и как как только наткнется на истинный результат, возвращает true, OR же вместо true возвращает само это вычисленное значение. Если все аргументы ложны, и ||, и OR возвращают 0.

Обычный &&: последовательно вычисляются аргументы, при встрече первого ложного результата возвращается 0, в AND - аналогично. Если результат вычисления всех аргументов истинен, && возвращает true, AND возвращает последний результат.

mes, у тебя функции неленивые (поправь, если я не права), для AND/OR это недопустимо... В лучшем случае это обернется легко обнаруживаемым сегфолтом, в худшем - сложно уловимыми побочными эффектами. По логике правильно.

volatile, Common Lisp. Не скриптовое, динамически типизированное.

math64, спасибо за помощь, сейчас буду разбираться...

boostcoder, тебе вообще огромное спасибо, сейчас тоже потыкаю твой последний вариант... Я вот сижу смотрю на раскрытие макроса и понимаю, что его аргументы (b1)(b2)(b3) будут вычисляться далеко не один раз... Значит нужно вначале раскрытия генерировать примерно следующее:
Код

typeof(b1) __tmp_1=b1;
typeof(b2) __tmp_2=b2;
typeof(b3) __tmp_3=b3;


И потом внутри мега ?:-конструкции использовать __tmp_X вместо bX. Мне сложно судить наверняка, но при нынешнем однопроходном раскрытии макроса это нереально. И отчасти вдогонку к этому, не мог бы ты объяснить без привязки к BOOST_PP, каким образом препроцессор си раскрывает макрос macro((b1)(b2))? То есть получается, он не просто разбивает входные аргументы, а распарсивает выражение...

Автор: boostcoder 5.2.2012, 22:45
Цитата(newbee @  5.2.2012,  22:23 Найти цитируемый пост)
(b1)(b2)(b3) будут вычисляться далеко не один раз... Значит нужно вначале раскрытия генерировать примерно следующее:

и выражения перестанут быть ленивыми.

ты это.. протесть то что у меня получилось, чтоб я убедился в том что правильно тебя понял и сделал. потом подумаем над доделками.

Цитата(newbee @  5.2.2012,  22:23 Найти цитируемый пост)
(b1)(b2)

в терминах boost.preprocessor - это последовательность. я же, итерируюсь по последовательности, и на каждой итерации раскрываю часть общего выражения.

Добавлено через 10 минут и 1 секунду
Цитата(newbee @  5.2.2012,  22:23 Найти цитируемый пост)
при нынешнем однопроходном раскрытии макроса это нереально.

можно дважды пройтись по последовательности.

Автор: volatile 5.2.2012, 23:56
Цитата(newbee @  5.2.2012,  22:23 Найти цитируемый пост)
Common Lisp. Не скриптовое, динамически типизированное.

Ну да. динамически типизированное. там это имеет практический смысл.

В С++ даже если и получиться написать (кстати неплохие варианты тут предлагали, ребята постарались!)
но использовать это почти не получится.

Все аргументы должны быть приводимы к одному типу, и кроме того еще и к bool (если я правильно понял..)
Где это можно использовать?
Не, ну можно конечно что-то придумать такое, где такое применить, но это имхо, искусственное притягивание за уши.
На приктике (при статической типизации) это практически бемполезная конструкция, имхо конечно.

Автор: newbee 6.2.2012, 08:44
boostcoder, я поэксперементировала с твоими вариантами, с точки зрения логики раскрытия все правильно! Ты прав, сразу раскрывать все аргументы нельзя - привет, ленивость! Но нашлась мысля smile Макросы можно разворачивать в ({})-форму, это расширение GCC, тогда на каждой итерации можно сначала вычислить результат, а потом его проверять!
Код
std::cout<<(1?({int res=foo();res?res:-1;}):0)<<std::endl;//просто пример ({})


Цитата(boostcoder @  5.2.2012,  23:45 Найти цитируемый пост)
в терминах boost.preprocessor - это последовательность. я же, итерируюсь по последовательности, и на каждой итерации раскрываю часть общего выражения.
Это я поняла по кодуsmile Мне любопытно, каким образом буст обманывает препроцессор и итерирует не по аргументам, а по свой скобочной коллекции. Интуиция подсказывает, что внутри это оборачивается в вызов другого макроса, очередной скобочный аргумент передается ему в качестве аргумента... Но как это происходит не пойму smile Исходники буст-препроцессора я не осилила, поэтому и любопытствую, что за трюк такой... Если не сложно.

Цитата(volatile @  6.2.2012,  00:56 Найти цитируемый пост)
а приктике (при статической типизации) это практически бемполезная конструкция, имхо конечно.
А на моей практике это очень нужная конструкция. Мы с тобой просто программируем по-разному, которая экономит много строк кода. Где-то на первой странице я приводила немного надуманый, но наглядный пример.

Автор: boostcoder 6.2.2012, 09:34
Цитата(newbee @  6.2.2012,  08:44 Найти цитируемый пост)
Макросы можно разворачивать в ({})-форму, это расширение GCC

не знал. попробую.

Цитата(newbee @  6.2.2012,  08:44 Найти цитируемый пост)
Интуиция подсказывает, что внутри это оборачивается в вызов другого макроса, очередной скобочный аргумент передается ему в качестве аргумента.

именно так.

к примеру простой макрос 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 секунд
Цитата(newbee @  6.2.2012,  08:44 Найти цитируемый пост)
Макросы можно разворачивать в ({})-форму, это расширение GCC

хм..
http://liveworkspace.org/code/35bcbcc90f05a2d8bd71d9b551f41499

дай ссылку на описание расширения.

Автор: newbee 6.2.2012, 09:53
Цитата(boostcoder @  6.2.2012,  10:34 Найти цитируемый пост)
дай ссылку на описание расширения. 
У тебя включен pedantic.

http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html

Компилируй с -std=gnu++98 или -std=gnu++0x

Автор: boostcoder 6.2.2012, 10:04
Цитата(newbee @  6.2.2012,  09:53 Найти цитируемый пост)
У тебя включен pedantic.

угу.

в общем работает.
попробую доделать..

Добавлено через 2 минуты и 31 секунду
mes, а Вы свой вариант будите доделывать? просто любопытно посмотреть на решение.
я тут еще подумал... для функционального программирования в с++, разработали http://www.boost.org/doc/libs/1_48_0/libs/phoenix/index.html. еще попробую с его помощью решить задачу.

Автор: mes 6.2.2012, 10:13
boostcoder, мой вариант придет к буст лямбде smile

Цитата(boostcoder @  6.2.2012,  09:04 Найти цитируемый пост)
 разработали boost.phoenix.

еще не приходилось сталкиваться smile


Автор: boostcoder 6.2.2012, 10:14
Цитата(mes @  6.2.2012,  10:13 Найти цитируемый пост)
мой вариант придет к буст лямбде

 smile 

Автор: boostcoder 9.2.2012, 01:28
newbee, итак.
давай посмотрим на препроцессированный вариант твоих тестов:
Код

int main() {
   int b1=0, b2=1, b3=2;

   std::cout << Ext_OR((b1)(Ext_AND((b2)(b1)))(b3)) << std::endl; //wait: 2; recieve: 2
   std::cout << Ext_OR((b1)(Ext_AND((b1)(b2)))(b3)) << std::endl; //wait: 2; recieve: 2
}

результат:
Код

int main() {
   int b1=0, b2=1, b3=2;

   std::cout << ( (b1) ? (b1) : (( !(b2) ? (b2) : ( b1 ) )) ? (( !(b2) ? (b2) : ( b1 ) )) : ( b3 ) ) << std::endl;
   std::cout << ( (b1) ? (b1) : (( !(b1) ? (b1) : ( b2 ) )) ? (( !(b1) ? (b1) : ( b2 ) )) : ( b3 ) ) << std::endl;
}


теперь нужно выявить вложенность "скопов" для того чтоб определить в каком скопе какое выражение должно вычисляться...

Добавлено @ 01:32
лишние скобки уберем..

Добавлено @ 01:36
вот что получилось:
Код

int main() {
   int b1=0, b2=1, b3=2;

   std::cout << (
      (b1)
      ?(b1)
         :!(b2)
            ?(b2)
               :(b1)
            ?!(b2)
               ?(b2)
                  :(b1)
               :(b3)
   ) << std::endl;

   std::cout << (
      (b1)
      ?(b1)
         :!(b1)
            ?(b1)
               :(b2)
            ?!(b1)
               ?(b1)
                  :(b2)
               :(b3)
   ) << std::endl;
}


Автор: newbee 9.2.2012, 11:03
boostcoder, у тебя сложно раскрывается AND. Я для наглядности буду возвращать нули вместо самих вычисленных значений.

Код

(and b1 b2 b3) -> b1?(b2?(b3?b3:0):0):0 // так имхо логичнее
(or b1 b2 b3) -> b1?b1:(b2?b2:(b3?b3:0)) //у тебя по-моему так и есть


Теперь... Смотри, внутри OR и AND излишне следовать правилу раскрытия элемента последовательности x?x: Если x - вложенный AND или OR, его можно прямо встроить в выражение. Я не знаю, можно ли это сделать на дефайнах... Это необязательно. Таким образом твой пример принял бы форму
Код

(or b1 (and b1 b2) b3) -> b1?b1:(b1?(b2?b2:0):(b3?b3:0))
/* или
   if?
     then
    :else
 */
b1?
  b1
 :(b1?
     (b2?
        b2
       :0)
    :(b3?
        b3
       :0))


Теперь давай подумаем со скопами...

Код

(and b1 b2 b3) ->  b1?(b2?(b3?b3:0):0):0 -> 

b1?
  (b2?
     (b3?
        b3
       :0)
    :0)
 :0 ->

({typeof(b1) _1=b1;
  _1?
    ({typeof(b2) _2=b2;
      _2?
        ({typeof(b3) _3=b3;
          _3?
            _3
           :0;})
       :0;})
   :0;})


И аналогично должно быть с OR. Потом напишу, если надо. Я нигде не накосячила?

Автор: boostcoder 9.2.2012, 13:19
вроде въехал..

Цитата(newbee @  9.2.2012,  11:03 Найти цитируемый пост)
Я нигде не накосячила?

по моему - нет.

Автор: math64 10.2.2012, 09:33
Код

#define OR(var,def) ({typeof(var) _tmp = (var); _tmp?_tmp:(def);})
#define TEST(var) OR(var,0)
#define AND(var1,var2) ((var1)?(var2):0)
int main() {
int v1 = 1, v2 = 2, v3 = 3;
// v1 or v2 or v3
cout << OR(v1,OR(v2,TEST(v3))) << endl;
// v1 and v2 and v3
cout << AND(v1,AND(v2,TEST(v3))) << endl;
// v1 and (v2 or v3)
cout << AND(v1,OR(v2,TEST(v3))) << endl;
// v1 or (v2 and v3)
cout << OR(v1,AND(v2,TEST(v3))) << endl;
}

(не проверял)

Автор: boostcoder 10.2.2012, 10:20
newbee, смотри какое дело.
код:
Код

int main() {
   int b1=0, b2=1, b3=2;
   std::cout << (
      ({typeof(b1) _1=b1;       // level +1
      _1?
         ({typeof(b2) _2=b2;    // level +2
            _2?
            ({typeof(b3) _3=b3; // level +3
               _3?
                  _3
               :0;
            })                  // level -3
            :0;
         })                     // level -2
         :0;
      })                        // level -1
   ) << std::endl;
}

как ты можешь видеть, тут вложенные скопы. но препроцессор не может рекурсию. он однопроходный.

идеи?

Автор: boostcoder 10.2.2012, 10:53
попробовал двумя проходами по последовательности генерировать сначала открывающиеся скопы, потом по той же последовательности, закрывающиеся.

на примере Ext_OR((b1)(b2)(b3)):
Код

({typeof(b1) _0 = b1; (_0) ? (_0) : ({typeof(b2) _1 = b2; (_1) ? (_1) : b3

вроде то, что надо.

но при попытке использовать вложенные макросы "Ext_OR ((b1)(b2)(b3)(Ext_OR ((b1)(b2)(b3))))" получаю ошибку препроцессора.
и правильно. при первом проходе еще ничего не сгенеренно. по этому препроцессор генерит нормально, не смотря на непарные скобки. но при втором проходе, он, "видя" такое ( smile ) синтаксически не правильное "произведение" - спотыкается.

идеи будут?

Добавлено через 2 минуты и 6 секунд
math64, не правильно. в твоем коде все равно выражения будут вычисляться не единожды.

Автор: newbee 10.2.2012, 12:57
Бустик, я совсем запуталась в твоих буст-пппроблемах :(

Сделала OR сама, ленивый, молодежный, современный! smile

Код

#include"PP_NARG.h"
#include"PP.h"
#include"PP_OR.h"

#define OR(...) PP_CONCATENATE(PP_OR_,PP_NARG(__VA_ARGS__))(__VA_ARGS__)

#include<iostream>

int foo(){
 std::cout<<__PRETTY_FUNCTION__<<std::endl;
 return 0;}

int bar(){
 std::cout<<__PRETTY_FUNCTION__<<std::endl;
 return 3;}

int main(){
 std::cout<<"out: "<<OR(foo(),OR(foo(),0),bar(),bar(),42)<<std::endl;
 std::cout<<"out: "<<OR(foo(),OR(bar(),foo()),bar(),bar(),42)<<std::endl;
 std::cout<<"out: "<<OR(42,OR(foo(),0),bar(),bar(),42)<<std::endl;
 return 0;}


Цитата
int foo()
int foo()
int bar()
out: 3
int foo()
int bar()
out: 3
out: 42


Критика, вопросы, предложения приветствуются!

PS. В архиве несколько вспомогательных файлов.

Автор: k0rvin 10.2.2012, 13:31
Цитата(tzirechnoy @ 3.2.2012,  17:25)
Шли бы Вы хаскель изучать, а? Тем более, что через монады это действительно делается, в том числе и в плюсах.

Жду решения на Хаскелле.

Автор: boostcoder 10.2.2012, 13:35
слуш.
а что если макрос будет раскрываться так?
Код

Ext_OR((b1)(b2)(b3));

...

({
typeof(b1) _0 = (b1);
typeof(b2) _1 = (b2);
typeof(b3) _2 = (b3);

(... ternarka ...);
})

т.е. все выражения будут вычисляться сразу. а?
или не актуально?

Добавлено через 2 минуты и 33 секунды
Цитата(newbee @  10.2.2012,  12:57 Найти цитируемый пост)
OR_AND.tar 20,00 Kb

а в архиве какие конкретно вирусы? smile

Добавлено через 5 минут и 48 секунд
вообще у тебя не плохо получилось. и без зависимости от буста smile

Автор: newbee 10.2.2012, 13:43
Цитата(boostcoder @  10.2.2012,  14:35 Найти цитируемый пост)

т.е. все выражения будут вычисляться сразу. а?
или не актуально?
Да нет, актуально. Интересно, как это будет выглядеть на бусте. Я когда тему создавала сразу предполагала, что ты родишь что-нибудь буст-препроцессорное...

Но сначала вычислять никак нельзя. Посмотри любой свой код, с нелинивыми операторами if, || и && он скорее всего рассыпется.

Добавлено через 2 минуты и 48 секунд
Цитата(boostcoder @  10.2.2012,  14:35 Найти цитируемый пост)
а в архиве какие конкретно вирусы?
Он несжатый)

Цитата(boostcoder @  10.2.2012,  14:35 Найти цитируемый пост)
вообще у тебя не плохо получилось.
Потому что нагенерировала специфичных под задачу макросов? Хотела сделать более обобщенный FOREACH, но там были бы сложности и неудобства. Или что еще плохо?

Автор: boostcoder 10.2.2012, 13:46
Цитата(newbee @  10.2.2012,  13:43 Найти цитируемый пост)
Но сначала вычислять никак нельзя. Посмотри любой свой код, с нелинивыми операторами if, || и && он скорее всего рассыпется.

ну да..

Добавлено через 11 секунд
ладно, думаю...

Автор: newbee 10.2.2012, 13:46
Блин, косая я. Не плохо получилось)) Неплохо, да! ))

Автор: boostcoder 10.2.2012, 13:47
Цитата(newbee @  10.2.2012,  13:43 Найти цитируемый пост)
Потому что нагенерировала специфичных под задачу макросов?

это не стёб был.
в самом деле нормально получилось. просто и понятно.

Добавлено через 26 секунд
Цитата(newbee @  10.2.2012,  13:46 Найти цитируемый пост)
косая я

 smile

Добавлено через 14 минут и 49 секунд
Цитата(newbee @  10.2.2012,  13:46 Найти цитируемый пост)
Неплохо

ну..мне простительно. русский мне не родной язык smile 

Автор: math64 10.2.2012, 18:37
Вычислятся быдут один раз. Проверяться и копироваться - да, много раз (при сложной формуле).
Идеи? Не пытаться делать макрос в переменным числом агрументов, генерирующих всё выражение, а набор макросов генерирующих фрагменты выражения.
Временной для запоминания переменной можно обойтись одной, поэтому можно опробовать что-то типа
Код

#define BEGIN(type) ({type _tmp;
#define BEGIN2(var) ({typeof(var) _tmp = var;
#define END ;})
#define AND == 0 ? 0 :
#define SAVE(var) (tmp = var)
#define OR   != 0  ? _tmp :

Возможно использовать набор макросов AND2(var1,var2), AND3(var1,var2,var3) и т.д.

Добавлено через 5 минут и 50 секунд
Цитата(boostcoder @  10.2.2012,  13:35 Найти цитируемый пост)
т.е. все выражения будут вычисляться сразу. а?

Неправильно. Выражения должны вычисляться только после проверки предыдущих:
Код

list<int> a;
count << AND(a.size(), a[0]) << endl; // нельзя вычислять a[0] до проверки размера списка


Автор: newbee 10.2.2012, 19:13
math64, я не понимаю, что у тебя за бегины и енды... Ты что-то недокопипастил?..

Добавлено через 10 минут и 41 секунду
Кстати... Есть ли у кого-нибудь идеи, как избавиться от typeof и ({}) расширений? На шаблонах или хз как еще... Возможно придется компилировать под винду, там я предпочитаю компилятор MSVC.

Автор: vol4ek 10.2.2012, 19:33
Цитата(newbee @  10.2.2012,  19:13 Найти цитируемый пост)
math64, я не понимаю, что у тебя за бегины и енды... Ты что-то недокопипастил?..


на VB похоже...  smile 

Автор: math64 10.2.2012, 19:52
Цитата(newbee @  10.2.2012,  19:13 Найти цитируемый пост)
math64, я не понимаю, что у тебя за бегины и енды... Ты что-то недокопипастил?

Отвечал на последнее сообщение предыдущей страницы - не заметил что есть ещё сообщения.
Это просто идеи, как построить макросы - не проработано до конца.
Если типы всех переменных одинаковы, можно использовать только одну временную переменную, которая объявлена в макросе BEGIN(type)
Макрос END закрывает объявление
Макросы, используемые в середине не проработаны.
Идея c AND2(), AND3(), OR2(), OR3() - уже не актуальна, Вы сделали лучше.
Как избавиться от ({}) - я уже предлагал - класс Saver, его можно переделать, чтобы был синглетоном и замоминал всё что можно как Variant, но typeof() всё равно нужен, чтобы получить запомненное значение нужного типа. Но если комплятор поддерживает ({}) - лучше использовать их (в объявлении макросов - условная трансляция)

Автор: boostcoder 10.2.2012, 20:05
Цитата(math64 @  10.2.2012,  18:37 Найти цитируемый пост)
Неправильно.

не нужно повторять.

Цитата(math64 @  10.2.2012,  18:37 Найти цитируемый пост)
Не пытаться делать макрос в переменным числом агрументов, генерирующих всё выражение, а набор макросов генерирующих фрагменты выражения.

жуть какая-то) как же такое юзать? оО

Цитата(math64 @  10.2.2012,  19:52 Найти цитируемый пост)
Если типы всех переменных одинаковы

а если нет?

Автор: math64 10.2.2012, 21:14
Цитата(boostcoder @  10.2.2012,  20:05 Найти цитируемый пост)
не нужно повторять.

уже объяснял - не прочитал всё до конца
Цитата(boostcoder @  10.2.2012,  20:05 Найти цитируемый пост)
а если нет?

если нет -   x ? y : z всё равно не скомпилируется, или все должны приводиться к типу первого выражения, его и использовать, или объявить тип переменной самостоятельно.
Код

  int* a = 0;
  long* b = 0;
  void* p = a ? a : b; // error: conditional expression distinct pointer types ...

В этом случае тип результата нужно объявлять самостоятельно
Код

void* p = ({void* tmp; (tmp = a) ? tmp : (tmp = b) ? b : 0; });


Правда, есть случай, когда даже при одном типе объединять нельзя:
Код

int& foo();
int& bar();
int zero = 0;
int& rzero = zero;
int& r = ({ int&tmp = foo();
              tmp ? tmp :
              ({ int&tmp=bar();
                 tmp?tmp:rzero;
              });
            });

Но он тоже не компилируется - результат ({ }) не int&, а int

Автор: boostcoder 10.2.2012, 21:25
Цитата(math64 @  10.2.2012,  21:14 Найти цитируемый пост)
если нет -   x ? y : z всё равно не скомпилируется

да. туплю.

Автор: math64 11.2.2012, 08:46
Нужно доработать макросы AND и OR, чтобы принимали переменное число агрументов (как в PP_NARG.h или из boost) и моглм комбинироваться.
TEST используется для задания значения по умолчанию для обычных типов 
TESTR используется для задания значения по умолчанию для ссылок
для ссылок желательно обезопасить от порчи значение по умочанию.
Код

#define TEST(def,and_or) ({ typeof(def) _tmp = def; and_or; _tmp; })
#define AND(var1,var2) if(var1) if(typeof(var2) _and2=(var2)) _tmp = _and2;
#define OR(var1,var2) if(typeof(var1) _or = (var1)) _tmp = _or; else if(typeof(var2) _or=(var2)) _tmp = _or;
#define TYPEOFR(var) typeof(&(var))
#define TESTR(def,and_or) *({ typeof(&(def)) _tmp = &(def); and_or; _tmp; })
#define ANDR(var1,var2) if(var1) { typeof(&(var2)) _and = &(var2); if(*_and) _tmp = _and; }
#define ORR(var1,var2) { typeof(&(var1)) _or = &var1; if(*_or) _tmp = _or; else { typeof(&(var2)) _or=&(var2); if(*_or) _tmp = _or; }}

#include <iostream>
using namespace std;

int& foo() {
cout << "foo()" << endl;
static int res = 0;
return res;
}

int& bar() {
cout << "bar()" << endl;
static int res = 1;
return res;
}

int main() {

cout << TEST(0,OR(foo(),bar())) << endl;
cout << TEST(0,AND(foo(),bar())) << endl;
int zero = 0;
int& rzero = zero;
cout << "rzero:" << &rzero << endl;
cout << "foo():" << &foo() << endl;
cout << "bar():" << &bar() << endl;
TESTR(rzero,ORR(foo(),bar())) = 2;
int& r1 = TESTR(rzero,ORR(foo(),bar()));
cout << "r1:" << &r1 <<'='<< r1 << endl;
int& r2 = TESTR(rzero,ANDR(foo(),bar()));
cout << "r2:" << &r2 <<'='<< r2 << endl;
}


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)