boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 12.01.14 18:52
Оценка:
снова здравствуйте!

есть такой код:

#include <boost/preprocessor.hpp>

/***************************************************************************/

#define CONSTRUCT_CONCRETE_proc(name, tuple) /* макровызов обработки последовательности для proc-типов */ \
    myproc[name: BOOST_PP_TUPLE_ENUM tuple]

#define CONSTRUCT_CONCRETE_enum(name, tuple) /* макровызов обработки последовательности для enum-типов */ \
    myenum[name: BOOST_PP_TUPLE_ENUM tuple]

#define CONSTRUCT_PROCS(unused, idx, seq) /* тут конкатинируем 'CONSTRUCT_CONCRETE_' и 'proc' или 'enum', и экспандим его */ \
    BOOST_PP_EXPAND(BOOST_PP_CAT(CONSTRUCT_CONCRETE_, BOOST_PP_SEQ_ELEM(idx, seq)))

#define CONSTRUCT(name, seq) \
    struct name { \
        BOOST_PP_REPEAT( \
             BOOST_PP_SEQ_SIZE(seq) \
            ,CONSTRUCT_PROCS \
            ,seq \
        ) \
    }; /* struct name */

/***************************************************************************/

CONSTRUCT(
    type1
    ,
    (proc(m0, (float)))
    (proc(m1, (int, long)))
    (enum(mye1, (e0, e1, e2)))
)

/***************************************************************************/

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

сейчас, при препроцессировании, получаю такой код:
struct type1 {
    myproc[m0: BOOST_PP_CAT(BOOST_PP_TUPLE_REM_CTOR_O_, 1)(float)]
    myproc[m1: BOOST_PP_CAT(BOOST_PP_TUPLE_REM_CTOR_O_, 2)(int, long)]
    myenum[mye1: BOOST_PP_CAT(BOOST_PP_TUPLE_REM_CTOR_O_, 3)(e0, e1, e2)]
};

этот код полностью валиден, за исключением того, что эти строки начинающиеся с 'BOOST_PP_CAT' — должны обрабатываться препроцессором, чего не происходит.
не понимаю, от чего так?

спасибо.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: boost.preprocessor не разворачивает макровызовы, почему-то
От: Vain Россия google.ru
Дата: 12.01.14 20:16
Оценка:
Здравствуйте, niXman, Вы писали:

X>#define CONSTRUCT_PROCS(unused, idx, seq) /* тут конкатинируем 'CONSTRUCT_CONCRETE_' и 'proc' или 'enum', и экспандим его */ \

X> BOOST_PP_EXPAND(BOOST_PP_CAT(CONSTRUCT_CONCRETE_, BOOST_PP_SEQ_ELEM(idx, seq)))
Может так поможет?
BOOST_PP_EXPAND(BOOST_PP_CAT)(CONSTRUCT_CONCRETE_, BOOST_PP_SEQ_ELEM(idx, seq))
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 12.01.14 20:31
Оценка:
Здравствуйте, Vain, Вы писали:

V>Может так поможет?

V>
V>BOOST_PP_EXPAND(BOOST_PP_CAT)(CONSTRUCT_CONCRETE_, BOOST_PP_SEQ_ELEM(idx, seq))
V>

нет, не помогло. абсолютно без изменений.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: boost.preprocessor не разворачивает макровызовы, почему-то
От: Vain Россия google.ru
Дата: 12.01.14 23:28
Оценка:
Здравствуйте, niXman, Вы писали:

X>нет, не помогло. абсолютно без изменений.

Можно ещё проверить правда ли то, что выдал препроцессор пытается компилировать компилятор. Для этого можно результат препроцессора скормить опять компилятору и сравнить номера ошибок. Они должны совпадать.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[4]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.01.14 01:44
Оценка:
так код же не полностью препроцессирован. какой смысл его компилировать?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: boost.preprocessor не разворачивает макровызовы, почему-то
От: nen777w  
Дата: 13.01.14 09:37
Оценка: 18 (1)
Здравствуйте, niXman, Вы писали:

А если так:

/***************************************************************************/
#define CONSTRUCT_CONCRETE_proc(name, tuple) /* макровызов обработки последовательности для proc-типов */ \
    (name)(tuple)

#define CONSTRUCT_CONCRETE_enum(name, tuple) /* макровызов обработки последовательности для enum-типов */ \
    (name)(tuple)


#define GET_MACRO(sub_macro) myproc[BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,BOOST_PP_CAT(CONSTRUCT_CONCRETE_, sub_macro)),:) BOOST_PP_TUPLE_ENUM(BOOST_PP_SEQ_ELEM(1,BOOST_PP_CAT(CONSTRUCT_CONCRETE_, sub_macro)))]

#define CONSTRUCT_PROCS(unused, idx, seq) /* тут конкатинируем 'CONSTRUCT_CONCRETE_' и 'proc' или 'enum', и экспандим его */ \
    GET_MACRO(BOOST_PP_SEQ_ELEM(idx, seq))

#define CONSTRUCT(name, seq) \
struct name { \
    BOOST_PP_REPEAT( \
    BOOST_PP_SEQ_SIZE(seq) \
    ,CONSTRUCT_PROCS \
    ,seq \
    ) \
}; /* struct name */

/***************************************************************************/

CONSTRUCT(
    type1
    ,
    (proc(m0, (float)))
    (proc(m1, (int, long)))
    (enum(mye1, (e0, e1, e2)))
    )


Aутпут:

struct type1 { myproc[m0: float] myproc[m1: int, long] myproc[mye1: e0, e1, e2] };


Думаю иде должна быть ясна. По сути, раскрываем полученный сиквенс в конкретных макросах, макросом из вне.
Если нужно, можно "специализировать" какие то еще дополнительные аргументы в сиквенсе в самих CONSTRUCT_CONCRETE_proc/CONSTRUCT_CONCRETE_enum а раскрыть их в GET_MACRO

p.s.
Вся "сложность" этих макросов, то что в голове постоянно нужен держать одно очень важное правило — препроцессор штука однопроходная.
Со временем можно легко натаскаться и писать их будет значительно проще, особенно с такой мощной либой как boost::preprocessor
Re[2]: boost.preprocessor не разворачивает макровызовы, почему-то
От: nen777w  
Дата: 13.01.14 09:42
Оценка: 18 (1)
поправочка

#define CONSTRUCT_CONCRETE_proc(name, tuple) /* макровызов обработки последовательности для proc-типов */ \
    (name)(tuple)(myproc)

#define CONSTRUCT_CONCRETE_enum(name, tuple) /* макровызов обработки последовательности для enum-типов */ \
    (name)(tuple)(myenum)


#define GET_MACRO(sub_macro) BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(2,BOOST_PP_CAT(CONSTRUCT_CONCRETE_, sub_macro)), \
        [BOOST_PP_CAT(BOOST_PP_SEQ_ELEM(0,BOOST_PP_CAT(CONSTRUCT_CONCRETE_, sub_macro)),:) BOOST_PP_TUPLE_ENUM(BOOST_PP_SEQ_ELEM(1,BOOST_PP_CAT(CONSTRUCT_CONCRETE_, sub_macro)))] \
    )
Re[3]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.01.14 14:19
Оценка:
спасибо за ответ!

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

зы
а твой вариант у тебя препроцессируется нормально, без ошибок?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[2]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.01.14 15:02
Оценка:
Здравствуйте, nen777w, Вы писали:

N>важное правило — препроцессор штука однопроходная.

слышал это не единожды, но не уверен, что правильно понимаю. объясни и это, плиз
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[3]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 14.01.14 11:46
Оценка:
решил следующим образом:
1. формируем имя нужного макроса
2. извлекаем тьюпл с типами
3. производим макровызов подставляя тьюпл

вопрос закрыт.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[4]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.02.14 13:06
Оценка:
решить проблему — решил. переключился на другую задачу, а сейчас не могу найти где решение записал. с утра тыркаюсь, а заново решить не получается %)
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: boost.preprocessor не разворачивает макровызовы, почему-то
От: niXman Ниоткуда https://github.com/niXman
Дата: 08.02.14 14:29
Оценка:
фух, получилось %)

оставлю-ка я решение тут:

#include <boost/preprocessor.hpp>

/***************************************************************************/

#define YARMI_CONSTRUCT_INVOKER_OPEN_NS_ITEM(unused, data, elem) \
    namespace elem {

#define YARMI_CONSTRUCT_INVOKER_OPEN_NS(seq) \
    BOOST_PP_SEQ_FOR_EACH( \
         YARMI_CONSTRUCT_INVOKER_OPEN_NS_ITEM \
        ,~ \
        ,seq \
    )

#define YARMI_CONSTRUCT_INVOKER_CLOSE_NS_ITEM(unused1, unused2, data) \
    data

#define YARMI_CONSTRUCT_INVOKER_CLOSE_NS(seq) \
    BOOST_PP_REPEAT( \
         BOOST_PP_SEQ_SIZE(seq) \
        ,YARMI_CONSTRUCT_INVOKER_CLOSE_NS_ITEM \
        ,} \
    )

/***************************************************************************/

#define NAME_proc(...) \
    GEN_proc
#define NAME_code(...) \
    GEN_code

#define GEN_proc(name, tuple) \
    void name(BOOST_PP_TUPLE_ENUM(tuple)) {}

#define GEN_code(...) \
    __VA_ARGS__

#define GET_PROC_NAME(str) \
    BOOST_PP_CAT(NAME_, str)

#define ARGS_proc(...) \
    __VA_ARGS__
#define ARGS_code(...) \
    __VA_ARGS__

#define GET_PROC_ARGS_NAME(str) \
    BOOST_PP_CAT(ARGS_, str)

#define EXP(idx, name, args) \
    name(args)

#define YARMI_CONSTRUCT_INVOKER_IMPL_AUX(idx, item) \
    EXP(idx, GET_PROC_NAME(item), GET_PROC_ARGS_NAME(item))

#define YARMI_CONSTRUCT_INVOKER_IMPL(unused, idx, seq) \
    YARMI_CONSTRUCT_INVOKER_IMPL_AUX(idx, BOOST_PP_SEQ_ELEM(idx, seq))

/***************************************************************************/

#define YARMI_CONSTRUCT_INVOKER(reqns, name, seq, oposeq) \
    YARMI_CONSTRUCT_INVOKER_OPEN_NS(reqns) \
    \
    struct name { \
        BOOST_PP_REPEAT( \
             BOOST_PP_SEQ_SIZE(seq) \
            ,YARMI_CONSTRUCT_INVOKER_IMPL \
            ,seq \
        ) \
    }; \
    YARMI_CONSTRUCT_INVOKER_CLOSE_NS(reqns)

/***************************************************************************/

#define YARMI_CONSTRUCT( \
     reqns \
    ,reqname \
    ,reqseq \
    ,repns \
    ,repname \
    ,repseq) \
    \
    YARMI_CONSTRUCT_INVOKER( \
         reqns \
        ,reqname \
        ,reqseq \
        ,repseq \
    )

/***************************************************************************/

YARMI_CONSTRUCT(
    (ns1)(ns2)(ns3)(ns4),
    login_request
    ,
    (code(
        private: int v;
        public: login_request(int v)
            :v(v)
        {}
        void set_v(int r) { v = r; }
        const int get_v() const { return v; }
    ))
    (proc(login, (char, int, double)))
    (code(using int_pair = std::pair<int, int>;))
    (proc(login, (char, int, double, int_pair)))
    (proc(login2, (int, double)))
    ,
    (ns4)(ns3)(ns2)(ns1),
    login_reply
    ,
    (code(void f0(){} int f1(){} std::pair<int, int> f2(){}))
    (proc(login, (char, int, double)))
)

/***************************************************************************/


результат:
namespace ns1 {
namespace ns2 {
namespace ns3 {
namespace ns4 {
struct login_request {
private:
   int v;
public:
   login_request(int v)
      :v(v)
   {}

   void set_v(int r) { v = r; }
   const int get_v() const { return v; }

   void login(char, int, double) {}
   using int_pair = std::pair<int, int>;
   void login(char, int, double, int_pair) {}
   void login2(int, double) {}
}; // struct login_request
} // ns4
} // ns3
} // ns2
} // ns1



всем спасибо!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.