Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: макросы  (Прочитано 15759 раз)
0 Пользователей и 3 Гостей смотрят эту тему.
Mayor
Специалист

ru
Offline Offline

« : 26-04-2004 08:13 » 

Когда проект разрастается нередко возникает необходимость переписывать, модифицировать, вставлять части фактически уже написаного кода и програмирование постепенно превращается  в рутину , может быть со временем я в совершенстве овладею написанием классов , ну а пока ::

мне бы хотелось как-то расширить функциональность препроцессора VC 6.0 до уровня Borland TASM 5.0 , или может у кого есть на примете С компилятор с лучшей поддержкой макросов .
Записан

1n c0de we trust
Roman123
Гость
« Ответ #1 : 26-04-2004 19:27 » 

Цитата: Mayor
Когда проект разрастается нередко возникает необходимость переписывать, модифицировать, вставлять части фактически уже написаного кода и програмирование постепенно превращается  в рутину , может быть со временем я в совершенстве овладею написанием классов , ну а пока ::

мне бы хотелось как-то расширить функциональность препроцессора VC 6.0 до уровня Borland TASM 5.0 , или может у кого есть на примете С компилятор с лучшей поддержкой макросов .


Можно поинтересоваться, что имеется ввиду под "лучшей поддержкой макросов"  Вот такой я вот
VC их поддерживает, так как предписывает стандарт
Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 27-04-2004 06:04 » new

Воспользуйся каким-нибудь макроязыком, например m4

Сразу предупреждаю -- от применения навороченных макросов проблемы с разрастанием и прочим maintenance только усугубятся .

Гораздо полезнее для борьбы со сложностью освоить design patterns и refactoring.  На русском языке есть соответствующие книги, так и называются "Шаблоны проктирования" и "Рефакторинг".
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
grozny
Гость
« Ответ #3 : 27-04-2004 07:53 » 

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

Так что луче - взять компилятор с поддержкой частичной спецификации шаблонов, Например, не VC 6.0, а VC 7.1. бОльшая часть потребностей в макросах для генерации кода будет накрыта средствами языка, что всегда хорошо. Не то, что бы шаблоны были сильно лучше макросов по части генерации багов и запутыванию текста - шаблоны тоже надъязык, ломающий синтаксис.  Отлично

В общем, если мне очень хочется сваять макрос, я сначала проверяю архитектуру данных и иерархию классов . В 90% случаев обнаруживается логический изъян, устранение которого снимает всякий смысл использования макро. STL тому наглядный пример - как можно жить без макросов и при том исключить дублирование кода.
Записан
Mayor
Специалист

ru
Offline Offline

« Ответ #4 : 28-04-2004 01:56 » 

2 Roman123  
мне требуется использование в макросе :

- Директив условной трансляции (#ifdef )
- Директив генерации условной ошибки
- Директив выхода из макроса и перевода трансляции к указанной строке исходного текста (ENDM , GOTO)
- макросов в тч рекурсии
- обработки произвольного числа входных параметров в тч передача во вложеный макрос с N по последний параметр
- Директив FOR WHILE REPEAT
- Директив работы со строками (CAT/IN/SIZE/SUBSTR)
- Да и вообще всех директив препроцессора С

Все чего я пока достиг : генерация директивой #define строки со встаками туда параметров , при первой же попытке вставить в макрос с параметрами любую директиву препроцессора , он принимает ее за параметр и ругается ,что нет такого .


2 npak

Что такое рефакторинг ?

2 grozny

Что такое частичная спецификация шаблонов ?
Похоже я перед дилемой либо IDE VS , либо нормальные макросы, своя ide , свой препроцессор - на последнее уйдет год или полтора - проще на несколько раз переписать свой код .
Учитывая разницу наших уровней знаний мне избежать необходимости в макросах нереально , я даже не берусь расчитывать свой процент успешного обнаружени логического изъяна ; а дулирование кода кстати может обеспечить рост производительности , хотя ты уже наверное на том уровне когда производительность достигается не кодированием , а алгоритмами , но мне до этого тоже далеко .

Наверное начну я потихоньку изучать концепции ООП ...
Записан

1n c0de we trust
grozny
Гость
« Ответ #5 : 28-04-2004 04:55 » 

- лучше пользоваться
#define XXXX==1
...
#if (ХХХХ==1)
#endif
...
#if (ХХХХ==0)
...
#endif

Тогда при опечатке в параметре препроцессор сругается. А вот если опечататься в #ifdef ХХХХУ
...
#endif
, то препроцессор решит, что символ неопределён и тихо выключит весь блок. Не всегда легко понять, что происходит - ты думаешь, что этот блок работает, а вот и.. нет. :twisted:

Цитата

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


За счёт снижения стабильности и читабельности. Нынешние оптимизирующие компиляторы развернут циклы и встроят ф-ции намного луче человека. Ручная оптимизация такого типа нужна исключительно редко. Особенно с нынешними скоростями.  

пример рекурсии с использованием частичной специализации шаблона:
Записан
Roman123
Гость
« Ответ #6 : 28-04-2004 09:12 » 

Цитата: Mayor
2 Roman123  
мне требуется использование в макросе :

- Директив условной трансляции (#ifdef )
- Директив генерации условной ошибки

Это всё есть

Цитата: Mayor

- Директив выхода из макроса и перевода трансляции к указанной строке исходного текста (ENDM , GOTO)
- обработки произвольного числа входных параметров в тч передача во вложеный макрос с N по последний параметр
- Директив FOR WHILE REPEAT
- Директив работы со строками (CAT/IN/SIZE/SUBSTR)


Можешь привести пример, того как ты эти возможности используешь  Вот такой я вот
У тебя ведь есть задача и макросы это только способ её решить, причём не лучший в С++.
Если ты опишешь случаи когда ты используешь макросы, можно предложить варианты как решить задачу в которой ты их используешь естественно на С++ с помощью шаблонов, встроеных функций и наследования.
[/b]
Записан
npak
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 28-04-2004 11:31 » 

Цитата: Mayor

2 npak

Что такое рефакторинг ?

// skipped
Наверное начну я потихоньку изучать концепции ООП ...


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

Управляемое в данном контексте означает, что код переписывается не как бог на душу положит, а по определённым правилам.  

Некоторые очень уважаемые товарищи (в том числе, Бек, Фаулер и компания) проанализировали то, как они и их знакомые переписывают код, и обнаружили ряд приемов, до которых и самому несложно догадаться.  Приёмы были выделены в чистом виде, проанализированы, всё лишнее выкинуто, а то, что осталось, документировано.

После толково проведённого рефакторинга код упрощается, на себе проверял.  Кроме того, для ряда языков есть среды, поддерживающие отдельные приёмы рефакторинга (например, Eclipse для Java).

Что касается последней процитированной фразы, то это гораздо правильней, чем кажется на первый взгляд.  Макросы, как я понимаю, остались у тебя с давних времён, когда языковых средств было маловато.  Имея в руках такой мощный и гибкий язык, как C++, лучше освоить его, чем пытаться прикрутить несвойственные ему средства.

Это похоже на то, как пытаться к современному грузовику приделать колёса для езды по рельсам, аргументируя тем, что так ездят паровозы.  Изучайте мат. часть и всё приложится.
Записан

UniTesK -- индустриальная технология надежного тестирования.

http://www.unitesk.com/ru/
Mayor
Специалист

ru
Offline Offline

« Ответ #8 : 01-05-2004 02:17 » 

Цитата

- лучше пользоваться
#define XXXX==1
...
#if (ХХХХ==1)
#endif
...
#if (ХХХХ==0)
...
#endif

 
как засунуть это внутрь #define ?

Цитата

Mayor писал(а):
2 Roman123
мне требуется использование в макросе :

- Директив условной трансляции (#ifdef )
- Директив генерации условной ошибки
 

Это всё есть

 
как это написать ( можно пример если макрос с параметрами ) ?


Цитата

Макросы, как я понимаю, остались у тебя с давних времён, когда языковых средств было маловато. Имея в руках такой мощный и гибкий язык, как C++, лучше освоить его, чем пытаться прикрутить несвойственные ему средства.

 


Вообще-то , я начинал изучение программирования Win32 с asm , мне нравилось использовать макросы , незаметно я перещел на С ... недавно прочитал книжку по дискретной математике , ничерта не понял и чтобы упорядочить свои знания решил на фоне прочитаного вычислить сборку кубика Рубика , создал его структуру , функцию его отображения на базе консоли , начал работать над вращением , потом вдруг ударился в реверсинг , когда вернулся обнаружил некоторые функции в программах реверсировать легче чем понять то , что я понаписал в исходниках   , неговоря уже об том, чтоб пореюзать уже написаное , в общем то что более менее понятно оставил , от остального избавился путем абстрагирования до уровня интерфейса ( начал переписывать непонятное  на С++ ) и тут меня начали доставать методы (см ниже) .

Цитата

Можешь привести пример, того как ты эти возможности используешь  
У тебя ведь есть задача и макросы это только способ её решить, причём не лучший в С++.
Если ты опишешь случаи когда ты используешь макросы, можно предложить варианты как решить задачу в которой ты их используешь естественно на С++ с помощью шаблонов, встроеных функций и наследования.

 



1. наиболее часто требовалось организовать циклы внутри которых считывать\записывать в 3D массив - после  Nного раза написания подобного метода начал пользоваться макросами с 2 параметрами -один макрос для чтения другой для записи :

void col::read_t(int side)
{

   if(side!=5)
   {
   for(int x=0;x<3;x++)
      this->trio
  • =cubic[side][Number]
  • ;
   }
   else
   {
      for(int x=0;x<3;x++)
      this->trio[2-x]=cubic[side][Number]
  • ;
   }


}

когда писать подобное меня окончательно достало стал использовать :
#define wr( x0, x1 ) for(int x=0;x<3;x++) cubic[side][x0][x1]=trio
  • ;
#define rd( x0, x1 ) for(int x=0;x<3;x++) trio
  • =cubic[side][x0][x1];

2. даллее появился метод , который в соответствии с rt var вызывал определенный макрос (типа 1.) с определенными параметрами - на asm это бы решилось элементарным рекурсивным макросом с произвольным числом параметров , тут пришлось использовать несколько if ( var==...) macro ( ...,...) :

   if (side==1)
   {
      rd ( x , 2-Number )
   }

   if (side==2)
   {
      rd ( Number , x )
   }

   if (side==4)
   {
      rd ( 2-x , Number )
   }

   if (side==3)
   {
      rd ( 2-Number , 2-x )
   }

В принципе можно предугадать во время компиляции , периодичность side при вызове метода которому принадлежит вышеизложенный код и заменить этот класс и 3 ему родственных на 3 функции + N количество поддерживающих функций , но потом будет не понять что откуда вызывать и более того эти функции 3 раза подряд писать вручную писать утомительно , а породить подобное макросом из мне известных компиляторов сможет только tasm (правда,пришлось бы изрядно поломать голову над написанием макроса) , так что пришлось жертвовать быстродействием в пользу удобочитаемости исходника ...


3. затем как и в 2. появилась пара методов которые в соответствии со значением rt var создавал объект  и потом вызывал одни и теже его методы

   int x;
   x=*pC+*(pC+1) -'0'-'0';
   if(x==1)
   {
      col t1(*(pC+2)-'0');
      if( *pC > *(pC+1))
         t1.rev();
      t1.rotate();
   }

   if(x==2)
   {
      row t1(*(pC+2)-'0');
      if( *pC > *(pC+1))
         t1.rev();
      t1.rotate();
   }

   if(x==3)
   {
      limb t1(*(pC+2)-'0');
      if( *pC > *(pC+1))
         t1.rev();
      t1.rotate();
   }
   
4. Еще постоянно требовалось переписывать циклы типа :

   for(int side =0;side<6;side++)
   {
      for(int y=0;y<3;y++)
      {
         for(int x=0;x<3;x++)
         {
            ...
            
            
         }
      }
   }
   
которые я использую при поиске , инициализации , сравнении , но в принципе здесь я смирился с постоянным выделением, копированием , вставкой .



Цитата

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


Писать на С++ оказалось проще, понятнее , и не смотря на мешанину структурного и объектно-ориентированого подходов в одном проекте , я стал неплохо ориентироваться в написаном .
С другой стороны , приблизительные потери в быстродействии при переходе на ОО стиль програмирования я оцениваю в 2-3 порядка .
И в ходе решения поставленной задачи я в первую очередь планирую воспользоваться простым перебором вариантов вращения ,если учесть степенную зависимость алгоритма перебора от числа последовательных вращений , то мне очень любопытно за сколько времени комп проанализирует все комбинации , минимально необходимого 4х кратного вращения.
Записан

1n c0de we trust
grozny
Гость
« Ответ #9 : 01-05-2004 05:16 » 

Цитата

как засунуть это внутрь #define ?

Я фигню-с написал в прошлый раз - имелось в виду вот что:

#define XXXX 1
...
#if (ХХХХ==1)
#endif
...
#if (ХХХХ==0)
...
#endif


Вот совсем наглядный пример условной компиляции (типа, в правильном стиле, с защитой от опечаток в условии)

Код:

#define BLAH 2
#if )BLAH==1:
#   error BLAH is 1
#elif )BLAH==2:
#   error BLAH is 2
#endif BLAH


результат компиляции будет таким:

fatal error C1189: #error : BLAH is 2

что говорит о том, что первый #error мы благополучно миновали. Ну и далее ставится нужный код вместо #error. Если охота напечатать сообщение о том, какая именно ветка компилируется без фатальной остановки, то пользуйтесь #pragma message вместо #error

 
Цитата

когда писать подобное меня окончательно достало стал использовать :
#define wr( x0, x1 ) for(int x=0;x<3;x++) cubic[side][x0][x1]=trio
  • ;
#define rd( x0, x1 ) for(int x=0;x<3;x++) trio
  • =cubic[side][x0][x1];

Есть же ключевое слово inline:
Код:

class col
|
   inline void wr) x0, x1 : |for)int x=0;x<3;x++: cubic[side([x0([x1(=trio[x(;"
   inline void rd) x0, x1 : |for)int x=0;x<3;x++: trio[x(=cubic[side([x0([x1(;"
";

Вот так например. Можно и не писать inline в некоторых случая компилятор сам разберётся. Читай хелп по inline.

Цитата

С другой стороны , приблизительные потери в быстродействии при переходе на ОО стиль програмирования я оцениваю в 2-3 порядка

Либо оценка слишком приблизительная, либо что-то не так в коде - 2 раза  Я шокирован! - слишком много. Пилите.  Отлично

Значительный кусок нашего драйвера (немаленького по размерам и функциональности) написан на С++. Замедления либо нету вообще (в сильно оптимизированных кусках без виртуальных ф-ций/классов, вызовы процедур и т.п.) и есть ускорение 5-6% (сравнительно с рукописным ассемблером), либо (в кусках с активном пользовании виртуальными классами/ф-циями) в районе 3-5%. Мерилось и постоянно меряется всякими Vtune, тестами и пр. Ну и там, где совсем критично, можно всегда вставить ассемблер. А критичный по времени исполнения код составляет не более 10% программы и, как правило, плоский неструктурированный кусок в теле цикла.

Цитата

И в ходе решения поставленной задачи я в первую очередь планирую воспользоваться простым перебором вариантов вращения ,если учесть степенную зависимость алгоритма перебора от числа последовательных вращений , то мне очень любопытно за сколько времени комп проанализирует все комбинации , минимально необходимого 4х кратного вращения.

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

Помнится, на РС ХТ была программка для собирания кубика (называлась соответственно Rubik). Работала достаточно быстро, чтобы не устать ждать. Минута или около того на сбор кубика из произвольной позиции. Так что задачка совершенно нетребовательна к производительности (на современных ЦП)
Записан
Mayor
Специалист

ru
Offline Offline

« Ответ #10 : 02-05-2004 05:53 » 

Цитата

Код:

#define BLAH 2
#if (BLAH==1)
#   error BLAH is 1
#elif (BLAH==2)
#   error BLAH is 2
#endif BLAH

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



Цитата

Цитата:

когда писать подобное меня окончательно достало стал использовать :
#define wr( x0, x1 ) for(int x=0;x<3;x++) cubic[side][x0][x1]=trio
  • ;
#define rd( x0, x1 ) for(int x=0;x<3;x++) trio
  • =cubic[side][x0][x1];


Есть же ключевое слово inline:
Код:

class col
{
   inline void wr( x0, x1 ) {for(int x=0;x<3;x++) cubic[side][x0][x1]=trio
  • ;}
  inline void rd( x0, x1 ) {for(int x=0;x<3;x++) trio
  • =cubic[side][x0][x1];}
};
 

Вот так например. Можно и не писать inline в некоторых случая компилятор сам разберётся. Читай хелп по inline.

 
этот вариант точно не подходит потому-что у меня x0 или x1  имеет в своем составе x , например,  rd (2-x, num ) , где num , к примеру,  аргумент функции  в которую вставлен макрос , а x переменая цикла , мне такие циклы нужены не для того чтобы во весь массив trio занести одно и то же значение , а для сохранения\переноса одной из осей 3d массива cubic[6][3][3] , т.о. я этими 2 макросами порождаю  8 функции ,  мне вместо того чтобы придумывать им названия  проще где надо вставлять макрос с параметрами
А кстати , хорошая идея в макрос дописать inline , хотя VS 6 до inline наверное нет дела .



Цитата

Цитата:

С другой стороны , приблизительные потери в быстродействии при переходе на ОО стиль програмирования я оцениваю в 2-3 порядка
 

Либо оценка слишком приблизительная, либо что-то не так в коде - 2 раза  - слишком много. Пилите.  

 
естественно , в 100 - 1000 раз с потолка взял , мне такое теоретически не расчитать , тут дело не в коде, а в используемом алгоритме .
 До того как я заценил приемущества мат. части, я баловался с программами сортировки , мой кривой алгоритм 4 мб обрабатывал бы 3 дня , потом я в инете наткнулся на QiuckSort , придуманый наверное лет за 15-20  до моего рождения ,  не поняв его, вставил в свою программу так он за несколько секунд все обработал .
 
 
 
Цитата

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

 
 Хм теория групп , не встречал , надо будет название запомнить .
 
 
Цитата

Помнится, на РС ХТ была программка для собирания кубика (называлась соответственно Rubik). Работала достаточно быстро, чтобы не устать ждать. Минута или около того на сбор кубика из произвольной позиции. Так что задачка совершенно нетребовательна к производительности (на современных ЦП)

 
 Ну это если программа правильно написана , а я могу такого наворотить , что никакой компьютер за сто лет не расчитает , но речь не о том что бы написать программу для собирания кубика , это на хрен никому не надо ,  мне просто нужно в освоить практическое применение курса дискретной математики , на базе какого-нибудь реально сложного примера , а не тех из учебника, смотря на которые думаешь для чего вообще эта дискретная математика нужна .
 
А если в формате форума - то научиться писать повторно используемый , поддерживаемый  код , есстественно , исключив его  дублирование  , что без макросов мне пока не удается .
Записан

1n c0de we trust
Roman123
Гость
« Ответ #11 : 05-05-2004 22:44 » 

Цитата: Mayor

как засунуть это внутрь #define ?


зачем это засовывать в #define?

Цитата: Mayor


1. наиболее часто требовалось организовать циклы внутри которых считывать\записывать в 3D массив - после  Nного раза написания подобного метода начал пользоваться макросами с 2 параметрами -один макрос для чтения другой для записи :

void col::read_t(int side)
{

   if(side!=5)
   {
   for(int x=0;x<3;x++)
      this->trio
  • =cubic[side][Number]
  • ;
   }
   else
   {
      for(int x=0;x<3;x++)
      this->trio[2-x]=cubic[side][Number]
  • ;
   }


}

когда писать подобное меня окончательно достало стал использовать :
#define wr( x0, x1 ) for(int x=0;x<3;x++) cubic[side][x0][x1]=trio
  • ;
#define rd( x0, x1 ) for(int x=0;x<3;x++) trio
  • =cubic[side][x0][x1];


Пример grozny абсолютно правильный.
Аргументацию
Цитата: Mayor

этот вариант точно не подходит потому-что у меня x0 или x1 имеет в своем составе x , например, rd (2-x, num ) , где num , к примеру, аргумент функции в которую вставлен макрос , а x переменая цикла , мне такие циклы нужены не для того чтобы во весь массив trio занести одно и то же значение , а для сохранения\переноса одной из осей 3d массива cubic[6][3][3] , т.о. я этими 2 макросами порождаю 8 функции , мне вместо того чтобы придумывать им названия проще где надо вставлять макрос с параметрами

я не понял  Жаль
Использование макросов и встроенных функций в описаном примере абсолютно идентично! Т.е. код будет сгенерирован одинаковый. В чём тут проблема? :l_smile:

Цитата: Mayor

2. даллее появился метод , который в соответствии с rt var вызывал определенный макрос (типа 1.) с определенными параметрами - на asm это бы решилось элементарным рекурсивным макросом с произвольным числом параметров , тут пришлось использовать несколько if ( var==...) macro ( ...,...) :

   if (side==1)
   {
      rd ( x , 2-Number )
   }

   if (side==2)
   {
      rd ( Number , x )
   }

   if (side==4)
   {
      rd ( 2-x , Number )
   }

   if (side==3)
   {
      rd ( 2-Number , 2-x )
   }

В принципе можно предугадать во время компиляции , периодичность side при вызове метода которому принадлежит вышеизложенный код и заменить этот класс и 3 ему родственных на 3 функции + N количество поддерживающих функций , но потом будет не понять что откуда вызывать и более того эти функции 3 раза подряд писать вручную писать утомительно , а породить подобное макросом из мне известных компиляторов сможет только tasm (правда,пришлось бы изрядно поломать голову над написанием макроса) , так что пришлось жертвовать быстродействием в пользу удобочитаемости исходника ...


Тут можно предложить такой вариант
inline rd(int a, int b) {...}

int a,b;
switch (side){
case 1:
   rd(x, 2-Number);
    break;
case 2:
...
}

Менее многословно чем с if, а по скорости работы ничем не уступит варианту с макросом.
[/quote]

Цитата: Mayor

3. затем как и в 2. появилась пара методов которые в соответствии со значением rt var создавал объект  и потом вызывал одни и теже его методы

   int x;
   x=*pC+*(pC+1) -'0'-'0';
   if(x==1)
   {
      col t1(*(pC+2)-'0');
      if( *pC > *(pC+1))
         t1.rev();
      t1.rotate();
   }

   if(x==2)
   {
      row t1(*(pC+2)-'0');
      if( *pC > *(pC+1))
         t1.rev();
      t1.rotate();
   }

   if(x==3)
   {
      limb t1(*(pC+2)-'0');
      if( *pC > *(pC+1))
         t1.rev();
      t1.rotate();
   }


используй виртуальные функции.
   
class ICubeElement
{
public:
virtual ~ICubeElement(){}
virtual void rev() =0;
virtual void rotate() =0;
};

class col : public ICubeElement {
public:
  col(...) {...}
   void rev() {...}
   void rotate() {...}
};

class row : public ICubeElement {
public:
  row(...) {...}
   void rev() {...}
   void rotate() {...}
};

class limb : public ICubeElement {
public:
  limb(...) {...}
   void rev() {...}
   void rotate() {...}
};

...
int x, y;
x=*pC+*(pC+1) -'0'-'0';
y=*(pC+2)-'0';
ICubeElement* pElem;
switch(x){
case 1:
   pElem = new col(y);
   break;
case 2:
   pElem = new row(y);
   break;
case 3:
   pElem = new limb(y);
   break;
}
if( *pC > *(pC+1))
   pElem->rev();
pElem->rotate();

delete pElem;
...

Если не хочется создавать и убивать объекты в куче, то надо заранее создать по обекту каждого типа и вместо конструктора вызывать метод init(...) с теми же параметрами.
[/quote]

Цитата: Mayor

4. Еще постоянно требовалось переписывать циклы типа :

   for(int side =0;side<6;side++)
   {
      for(int y=0;y<3;y++)
      {
         for(int x=0;x<3;x++)
         {
            ...
            
            
         }
      }
   }
   
которые я использую при поиске , инициализации , сравнении , но в принципе здесь я смирился с постоянным выделением, копированием , вставкой .


в цыкле производиться какое-то действие с каждым элементом массива.

typedef int ***Cubic;
Cubic cubic;

пишем одну функцию
inline void apply(Cubic cubic, Func& func)
{
for(int side =0;side<6;side++)
{
   for(int y=0;y<3;y++)
   {
      for(int x=0;x<3;x++)
      {
      func(cubic[side][y]
  • );
      }
   }
}
}

class Func {
public:
 virtual void operator() (int& i) const =0;
};

class Inc : public Func {
public:
    Inc(int val):_val(val) {}
    void operator() (int& i) const { i += _val};
private:
   int _val;
};


теперь чтобы прибавить ко всем элементам 5 пишем

apply(cubic, Inc(5));

По эфективности этот код, опять же, ничем не уступает сгенереному с помощью макросов или copy/paste. Но! В нём проводиться полная в стиле С++ проверка типов.

Возможно, пример с прибавлением числа к каждому элементу не очень жизненный? Опиши подробней операции, я предложу вариант.

Сформулируй задачу которую ты решаешь, плз.

В завершение ещё раз хотел бы подчеркнуть, что я полностью согласен со Страуструпом в том, что от использования макросов в С++ в большинстве случаев можно отказаться не в ущерб скорости и удобочитаемости программы. Единтсвенное место для чего я часто их использую - это условная компиляция, в часности, стражи включения.
Записан
Mayor
Специалист

ru
Offline Offline

« Ответ #12 : 09-05-2004 04:02 » 

Цитата

Mayor писал(а):

как засунуть это внутрь #define ?
 
зачем это засовывать в #define?

 
Ну хотя бы для того , чтобы организовать рекурсию ; просто такая техника сильно расширяет функциональность макросов , да и вообще очень прикольно  генерить макрос в зависимости от условий.



Цитата

Пример grozny абсолютно правильный.
Аргументацию

я не понял  
Использование макросов и встроенных функций в описаном примере абсолютно идентично! Т.е. код будет сгенерирован одинаковый. В чём тут проблема?  

 



весь прикол в том , что у меня только-что в первый раз получилось , как говорил grozny : " обнаружить логический изъян, устранение которого снимает всякий смысл использования макро  " Улыбаюсь)

Более подробная аргументация:

допустим имеется 2d массив cubic[3][3] :

1 2 3
4 5 6
7 8 9

нужно из него считаль строку или столбец num , в прямом или обратном порядке в  1d массив trio[3] :

A B C

т.е. в :

#define rd( x0, x1 ) for(int x=0;x<3;x++) trio
  • =cubic[side][x0][x1];

один из параметров можно задавать через rt var  - это будет  номер строки или столбца , а другой фактически определяет функцию на этапе компиляции

Если нужно считать 0ю строку в прямом порядке вызывается :
num=0;

....

rd ( num , x)

// тогда trio={1,2,3}

Если нужно считать 2й столбец в обратном порядке вызывается :
num=2;

...

rd ( 2-x, num )

// тогда trio={9,6,3}


Пока я думал над вышеизложенным , оказалось, что использование массива для этих функций неприемлимо , все чтение можно запихнуть в 1 функцию :

class col
{
// c_elem cubic[6][3][3]
   inline void rd( c_elem *FirstElem,signed  int dNextElem ) {
   for(int x=0;x<3;x++,FirstElem+=dNextElem) {
   trio
  • =*FirstElem;
  }
};

что будет быстрее макроса rd(x0,x1) и наверняка компилятор даже избавится от цикла при оптимизации

Кстати, нет ли явной директивы , чтобы заставить компилятор раскрутить небольшой цикл , дублировав код  и избавившись от условных переходов Не понял




Цитата

...Менее многословно чем с if, а по скорости работы ничем не уступит варианту с макросом.

 


да, switch прикольнее сцепки if if if , хотя в немногословности  до рекурсивного макроса все равно не дотягивает  , но что поделаешь С не asm - буду switch использовать



Цитата

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

 

Хорошая идея , я наследование использовал ,чтобы код функций не переписывать , а тут несмотря на то что код функций полностью различается , интерфейс одинаковым  оказался ; действительно , эту часть придется переписать для повышения производительности , все таки есть небольшие издержки при создании объекта , превышающие снижение производительности из-за использования виртуальных функций , так что буду лучше указатель на базовый класс изменять в соответствии с условиями



Цитата

typedef int ***Cubic;
Cubic cubic;

 
я непонял, как cubic инициализировать  ?
cubic=   что дальше написать ?



Цитата

Сформулируй задачу которую ты решаешь, плз.

 


Я пытаюсь выяснить алгоритм сборки кубика Рубика , вернее заценить приимущества использовании мат. части в более-менее сложной задаче :

1. Создание структыры данных для модели Рубика

#ifndef el11
typedef struct el1{
   int number;
   int color;
   //el1 operator=(el1 &e);
} c_elem;
//typedef int side;
// в целях оптимизации подвергнется дальнейшим изменениям
#define el11
#endif

extern c_elem cubic[6][3][3];

2. Визуализация структуры кубика :
Пока реализовано  через STD_OUTPUT_HANDLE

3. Считывание из файла последовательности комманд на вращение и ее осуществление :
команда состоит из 3х unsigned char 1-сторона исходная 2- сторона назначения ( 1 и 2 из-за неоднозначности не могут быть противоположными ) 3 - номер строки, столбца или пояска для вращения

4. разбитие на классы эквивалентности последовательности комманд с целью анализа последовательностей вызывающих наименьшее не равное 0 число перемещений ( циклов ) :
пока на стадии обдумывания


Может кто скинет пару-тройку ссылок для изучения мат. части программирования ?
Записан

1n c0de we trust
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines