Побороть копипаст
От: Аноним  
Дата: 15.08.10 07:47
Оценка:
Имеется GUI, в котором штук 10 закладок, на каждой закладке таблица, тулбар, меню.
Я перечисляю эти таблицы

class MainWindow {
public:
enum {
Weapons , Planes, Resources,/*и т.д.*/ Last  
};
};


Хотелось бы на основе этого перечисления генерить в классе (а не набивать вручную), например, обработчики

void on_Weapon_Selected();
void on_Planes_Selected();
/*и т.д.*/

void on_Weapon_ToolBar_Click();
void on_Planes_ToolBar_Click();
/*и т.д.*/


Подскажите, как сделать макросом или с помощью шаблонов что-то типа:

ON_TABLE_SELECTED(Weapons , Planes, Resources)
ON_TOOLBAR_CLICK(Weapons ,  Planes, Resources)
Re: Побороть копипаст
От: lxa http://aliakseis.livejournal.com
Дата: 15.08.10 10:25
Оценка: 2 (1)
Я боюсь посоветовать такое:

#define GOODS_LIST \
    ITEM_DEFN(Weapons) \
    ITEM_DEFN(Planes) \
    ITEM_DEFN(Resources)

class MainWindow {
public:
#define ITEM_DEFN(item) item,
    enum {
        GOODS_LIST
        Last  
    };
#undef ITEM_DEFN
};

#define ITEM_DEFN(item) void on_##item##_Selected();
GOODS_LIST
#undef ITEM_DEFN

#define ITEM_DEFN(item) void on_##item##_ToolBar_Click();
GOODS_LIST
#undef ITEM_DEFN
Re: Побороть копипаст
От: morm Россия  
Дата: 15.08.10 10:26
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Имеется GUI, в котором штук 10 закладок, на каждой закладке таблица, тулбар, меню.

А>Я перечисляю эти таблицы

А>
А>class MainWindow {
А>public:
А>enum {
А>Weapons , Planes, Resources,/*и т.д.*/ Last  
А>};
А>};
А>


А>Хотелось бы на основе этого перечисления генерить в классе (а не набивать вручную), например, обработчики


А>
А>void on_Weapon_Selected();
А>void on_Planes_Selected();
А>/*и т.д.*/

А>void on_Weapon_ToolBar_Click();
А>void on_Planes_ToolBar_Click();
А>/*и т.д.*/
А>


А>Подскажите, как сделать макросом или с помощью шаблонов что-то типа:


А>
А>ON_TABLE_SELECTED(Weapons , Planes, Resources)
А>ON_TOOLBAR_CLICK(Weapons ,  Planes, Resources)
А>


Сделай класс MTab с обработчиком On_Click, отнаследую от него свои таблицы, запихай указатели в контейнер. В общем обработчике определяешь объект и вызываешь полиморфный метод On_Click.
Re[2]: Побороть копипаст
От: purser Россия  
Дата: 15.08.10 10:54
Оценка:
Это решение мне не нравится тем, что нужно объявлять классы, наследоваться от них. Сама задача ИМХО процедурного, если можно так выразиться, типа.
Сейчас пытаюсь осилить решение Ixa, похоже на то, что я хотел)

Здравствуйте, morm, Вы писали:

M>Сделай класс MTab с обработчиком On_Click, отнаследую от него свои таблицы, запихай указатели в контейнер. В общем обработчике определяешь объект и вызываешь полиморфный метод On_Click.
Re[2]: Побороть копипаст
От: purser Россия  
Дата: 15.08.10 11:38
Оценка:
Спасибо. А можно ли исходя из нижеописанного заиметь таким же образом определение:

const char* names= {"Weapons", "Planes", "Resources", NULL};



Здравствуйте, lxa, Вы писали:

lxa>Я боюсь посоветовать такое:


lxa>
lxa>#define GOODS_LIST \
lxa>    ITEM_DEFN(Weapons) \
lxa>    ITEM_DEFN(Planes) \
lxa>    ITEM_DEFN(Resources)

lxa>class MainWindow {
lxa>public:
lxa>#define ITEM_DEFN(item) item,
lxa>    enum {
lxa>        GOODS_LIST
lxa>        Last  
lxa>    };
lxa>#undef ITEM_DEFN
lxa>};

lxa>#define ITEM_DEFN(item) void on_##item##_Selected();
lxa>GOODS_LIST
lxa>#undef ITEM_DEFN

lxa>#define ITEM_DEFN(item) void on_##item##_ToolBar_Click();
lxa>GOODS_LIST
lxa>#undef ITEM_DEFN
lxa>
Re[2]: Побороть копипаст
От: Кодт Россия  
Дата: 15.08.10 11:57
Оценка:
Здравствуйте, lxa, Вы писали:

lxa>Я боюсь посоветовать такое:


И правильно боишься! Переопределение макросов — это адский ад.
Можно чуть-чуть перезаточить
#define DEFINE_ITEMS(how) \
  DEFINE_ITEM(how, Weapons) \
  DEFINE_ITEM(how, Planes) \
  DEFINE_ITEM(how, Resources)

#define DEFINE_ITEM(how, what) how(what)

#define ITEM_OF_ENUM(what) what,
#define DECLARE_ON_SELECTED(what) void on_##what##_Selected();
#define DECLARE_ON_CLICKED(what)  void on_##what##_Toolbar_Click();

class MainWindow
{
public:
  enum { DEFINE_ITEMS(ITEM_OF_ENUM) Last };
  DEFINE_ITEMS(DECLARE_ON_SELECTED);
  DEFINE_ITEMS(DECLARE_ON_CLICKED);
};


Но лучше всего — припахать Boost.Preprocessor
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/cat.hpp>


#define ITEMS  (Weapons)(Planes)(Resources) // PP SEQ - наиболее удобная форма

#define CAT3(a,b,c) BOOST_PP_CAT(a,BOOST_PP_CAT(b,c))

#define ITEM_OF_ENUM(r,data,elem)        elem,
#define DECLARE_ON_SELECTED(r,data,elem) void CAT3(on_,elem,_Selected)();
#define DECLARE_ON_CLICKED(r,data,elem)  void CAT3(on_,elem,_Clicked)();

class MainWindow
{
public:
  enum { BOOST_PP_SEQ_FOR_EACH(ITEM_OF_ENUM,_,ITEMS) Last };
  BOOST_PP_SEQ_FOR_EACH(DECLARE_ON_SELECTED,_,ITEMS)
  BOOST_PP_SEQ_FOR_EACH(DECLARE_ON_CLICKED,_,ITEMS)
};
Перекуём баги на фичи!
Re[3]: Побороть копипаст
От: Кодт Россия  
Дата: 15.08.10 12:02
Оценка:
Здравствуйте, purser, Вы писали:

P>Спасибо. А можно ли исходя из нижеописанного заиметь таким же образом определение:


P>
P>const char* names= {"Weapons", "Planes", "Resources", NULL};
P>


Опять же, BOOST_PP нам поможет
#define TEXTUAL(r,d,elem)  BOOST_PP_STRINGIZE(elem),

const char* names = { BOOST_PP_SEQ_FOR_EACH(TEXTUAL,_,ITEMS) NULL };
Перекуём баги на фичи!
Re[4]: Побороть копипаст
От: purser Россия  
Дата: 15.08.10 12:09
Оценка:
Спасибо. А штатным препроцессором можно ? Буст, к сожалению, пока нет возможности использовать..
Вы сказали, что такой стиль адский ад. Разве этот стиль не похож на lisp style ?

Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, purser, Вы писали:


P>>Спасибо. А можно ли исходя из нижеописанного заиметь таким же образом определение:


P>>
P>>const char* names= {"Weapons", "Planes", "Resources", NULL};
P>>


К>Опять же, BOOST_PP нам поможет

К>
К>#define TEXTUAL(r,d,elem)  BOOST_PP_STRINGIZE(elem),

К>const char* names = { BOOST_PP_SEQ_FOR_EACH(TEXTUAL,_,ITEMS) NULL };
К>
Re[3]: Побороть копипаст
От: lxa http://aliakseis.livejournal.com
Дата: 15.08.10 12:32
Оценка:
Здравствуйте, purser, Вы писали:

P>Спасибо. А можно ли исходя из нижеописанного заиметь таким же образом определение:


P>
P>const char* names= {"Weapons", "Planes", "Resources", NULL};
P>


Со "стрингайзером" бывают проблемы, но вроде здесь они не проявляются, Если использовать переработку Кодта ниже, наверно можно так:


#define DEFINE_ITEMS(how) \
  DEFINE_ITEM(how, Weapons) \
  DEFINE_ITEM(how, Planes) \
  DEFINE_ITEM(how, Resources)

#define DEFINE_ITEM(how, what) how(what)

#define ITEM_OF_ENUM(what) what,
#define DECLARE_ON_SELECTED(what) void on_##what##_Selected();
#define DECLARE_ON_CLICKED(what)  void on_##what##_Toolbar_Click();

class MainWindow
{
public:
  enum { DEFINE_ITEMS(ITEM_OF_ENUM) Last };
  DEFINE_ITEMS(DECLARE_ON_SELECTED);
  DEFINE_ITEMS(DECLARE_ON_CLICKED);
};


#define DECLARE_NAME(what)  #what,

const char* names[] = { DEFINE_ITEMS(DECLARE_NAME) NULL };
Re[5]: Побороть копипаст
От: Кодт Россия  
Дата: 15.08.10 12:39
Оценка:
Здравствуйте, purser, Вы писали:

P>Спасибо. А штатным препроцессором можно ? Буст, к сожалению, пока нет возможности использовать..


Буст_ПП — это просто гора макросов для штатного препроцессора!
Почему "нет возможности"? Религиозные соображения, или что?


P>Вы сказали, что такой стиль адский ад.


потому что
1) возникают тонкие зависимости от порядка определения, — такой код довольно тяжело сопровождать
2) у IDE сносит крышу от множественного определения символов, intellisence начинает спотыкаться

P>Разве этот стиль не похож на lisp style ?


Не знаю, что подразумевается под lisp style.
Это императивщина
#define FOO   BAR(x) BAR(y) BAR(z)

#define BAR(x) hello x    // присвоили глобальному имени BAR вот такое определение
FOO                       // воспользовались
#define BAR(x) world_##x  // присвоили новое значение
FOO                       // воспользовались новым значением

тогда как можно было бы написать функцию (макрос) высшего порядка — что, собственно, я и показал.
Перекуём баги на фичи!
Re[4]: Побороть копипаст
От: Кодт Россия  
Дата: 15.08.10 12:48
Оценка:
Здравствуйте, lxa, Вы писали:

lxa>Со "стрингайзером" бывают проблемы, но вроде здесь они не проявляются,

Эти проблемы состоят в том, что # применяется к недоразвёрнутому выражению.
Лечится с помощью косвенности
#define STR(x) STR_(x) // откладываем на один шаг, чтобы препроцессор успел выполнить все подстановки внутри x
#define STR_(x) #x

#define A(x) (x+x+x)
STR_(A(1)) // "A(1)"
STR(A(1))  // "(1+1+1)"


То же самое — с конкатенацией (##).
#define CAT(a,b) CAT_(a,b)
#define CAT_(a,b) a##b
Перекуём баги на фичи!
Re[6]: Побороть копипаст
От: purser Россия  
Дата: 15.08.10 12:55
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, purser, Вы писали:


P>>Спасибо. А штатным препроцессором можно ? Буст, к сожалению, пока нет возможности использовать..


К>Буст_ПП — это просто гора макросов для штатного препроцессора!

К>Почему "нет возможности"? Религиозные соображения, или что?

Сорри за дремучесть. Я почему-то подумал, что придется весь буст за собой тащить.


P>>Разве этот стиль не похож на lisp style ?


К>Не знаю, что подразумевается под lisp style.


повсеместное использование макросов, при чтении которых закипают мозги)
Re[7]: Побороть копипаст
От: Кодт Россия  
Дата: 15.08.10 13:42
Оценка:
Здравствуйте, purser, Вы писали:

P>Сорри за дремучесть. Я почему-то подумал, что придется весь буст за собой тащить.


Достаточно выковырять /boost/preprocessor/**
Это чисто хедеры.
Перекуём баги на фичи!
Re[3]: Побороть копипаст
От: Mr.Delphist  
Дата: 16.08.10 21:50
Оценка:
Здравствуйте, purser, Вы писали:

P>Это решение мне не нравится тем, что нужно объявлять классы, наследоваться от них. Сама задача ИМХО процедурного, если можно так выразиться, типа.

P>Сейчас пытаюсь осилить решение Ixa, похоже на то, что я хотел)

Если уж с такой точки зрения смотреть, то Вам DSL (Domain Specific Language) надобен.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.