Препроцессорные трюки.
От: okman Беларусь https://searchinform.ru/
Дата: 04.08.13 20:14
Оценка: 2 (1)
Привет !

Понадобилось тут мне сделать одну вещь на препроцессоре.
Быстро понял, что дальше примитивных ifdef особо ничего не знаю.
Заглянул ради интереса в Boost, увидел такой макрос
  Скрытый текст
// ty: EMPTY() | typename
#define BOOST_SCOPE_EXIT_AUX_IMPL(id, ty, traits) \
    BOOST_PP_LIST_FOR_EACH_I(BOOST_SCOPE_EXIT_DETAIL_TAG_DECL, id, \
            BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)) \
    BOOST_PP_LIST_FOR_EACH_I(BOOST_SCOPE_EXIT_DETAIL_CAPTURE_DECL, (id, ty), \
            BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)) \
    BOOST_PP_IIF(BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits), \
        BOOST_SCOPE_EXIT_DETAIL_TYPEDEF_TYPEOF_THIS \
    , \
        BOOST_PP_TUPLE_EAT(3) \
    )(id, ty, BOOST_SCOPE_EXIT_AUX_THIS_CAPTURE_T(id)) \
    struct BOOST_SCOPE_EXIT_DETAIL_PARAMS_T(id) { \
        /* interim capture types to workaround internal errors on old GCC */ \
        BOOST_PP_LIST_FOR_EACH_I(BOOST_SCOPE_EXIT_DETAIL_PARAM_DECL, (id, ty), \
                BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)) \
        BOOST_PP_EXPR_IIF(BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits), \
            typedef BOOST_SCOPE_EXIT_AUX_THIS_CAPTURE_T(id) \
                    BOOST_SCOPE_EXIT_AUX_THIS_T(id) ; \
        ) \
        BOOST_PP_LIST_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_MEMBER, id, \
                BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)) \
        BOOST_PP_EXPR_IIF(BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits), \
            BOOST_SCOPE_EXIT_AUX_THIS_T(id) \
                    BOOST_SCOPE_EXIT_DETAIL_PARAM_THIS(id) ; \
        ) \
        BOOST_SCOPE_EXIT_AUX_PARAMS_T_CTOR(id, ty, \
                BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits), \
                BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits)) \
    } BOOST_SCOPE_EXIT_AUX_PARAMS(id) \
        BOOST_SCOPE_EXIT_AUX_PARAMS_INIT(id, \
                BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits), \
                BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits)) \
    ; \
    ::boost::scope_exit::detail::declared< \
        ::boost::scope_exit::detail::resolve< \
            sizeof(BOOST_SCOPE_EXIT_AUX_ARGS) \
        >::cmp1<0>::cmp2 \
    > BOOST_SCOPE_EXIT_AUX_ARGS; \
    BOOST_SCOPE_EXIT_AUX_ARGS.value = &BOOST_SCOPE_EXIT_AUX_PARAMS(id); \
    struct BOOST_SCOPE_EXIT_AUX_GUARD_T(id) { \
        BOOST_SCOPE_EXIT_DETAIL_PARAMS_T(id)* boost_se_params_; \
        BOOST_SCOPE_EXIT_AUX_GUARD_T(id) (void* boost_se_params) \
            : boost_se_params_( \
                    (BOOST_SCOPE_EXIT_DETAIL_PARAMS_T(id)*)boost_se_params) \
        {} \
        ~BOOST_SCOPE_EXIT_AUX_GUARD_T(id)() { \
            boost_se_body( \
                BOOST_PP_LIST_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_ARG, id, \
                        BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)) \
                BOOST_PP_COMMA_IF(BOOST_PP_BITAND(BOOST_PP_LIST_IS_CONS( \
                        BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)), \
                        BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits))) \
                BOOST_PP_EXPR_IIF(BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS( \
                        traits), \
                    boost_se_params_->BOOST_SCOPE_EXIT_DETAIL_PARAM_THIS(id) \
                ) \
            ); \
        } \
        static void boost_se_body( \
            BOOST_PP_LIST_FOR_EACH_I(BOOST_SCOPE_EXIT_AUX_ARG_DECL, (id, ty), \
                    BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)) \
            BOOST_PP_COMMA_IF(BOOST_PP_BITAND(BOOST_PP_LIST_IS_CONS( \
                    BOOST_SCOPE_EXIT_AUX_TRAITS_CAPTURES(traits)), \
                    BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits))) \
            BOOST_PP_EXPR_IIF(BOOST_SCOPE_EXIT_AUX_TRAITS_HAS_THIS(traits), \
                ty BOOST_SCOPE_EXIT_DETAIL_PARAMS_T(id):: \
                        BOOST_SCOPE_EXIT_AUX_THIS_T(id) this_ \
            ) \
        )

и сразу "поехал домой".

В общем, можете посоветовать какой-нибудь интересный материальчик по теме ?
Только без Boost.PP — там разобраться может только маньяк.

Здесь был:
https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms

Это читал:
http://www.amazon.com/Template-Metaprogramming-Concepts-Techniques-Beyond/dp/0321227255

Спасибо.
Re: Препроцессорные трюки.
От: Evgeny.Panasyuk Россия  
Дата: 04.08.13 20:30
Оценка:
Здравствуйте, okman, Вы писали:

O>Только без Boost.PP — там разобраться может только маньяк.


Без Boost.PP трудно писать кросс-платформенный код (на макросах) — например потому что у MSVC много багов в препроцессоре, и тот код который работает на MSVC может быть некорректным с точки зрения ISO и не работать GCC.
Boost.PP выступает в роли абстракции от конкретного препроцессора, разруливая implementation-specific проблемы под капотом.
Re: Препроцессорные трюки.
От: zaufi Земля  
Дата: 04.08.13 20:41
Оценка: +1
Здравствуйте, okman, Вы писали:

O>В общем, можете посоветовать какой-нибудь интересный материальчик по теме ?

O>Только без Boost.PP — там разобраться может только маньяк.

а в чем ты собрался разбираться? в использовании он (BOOST_PP) достаточно прост по большей части, доки вполне себе понятные...
или ты хочешь написать свой аналог??
Re[2]: Препроцессорные трюки.
От: okman Беларусь https://searchinform.ru/
Дата: 05.08.13 07:24
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Без Boost.PP трудно писать кросс-платформенный код (на макросах)


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

EP>у MSVC много багов в препроцессоре


Например ?
Re[2]: Препроцессорные трюки.
От: okman Беларусь https://searchinform.ru/
Дата: 05.08.13 07:29
Оценка:
Здравствуйте, zaufi, Вы писали:

Z>или ты хочешь написать свой аналог??


Хотел бы научиться с помощью препроцессора преодолевать некоторые ограничения самого С++.
Как это делается в Boost.
Re: Препроцессорные трюки.
От: ArtDenis Россия  
Дата: 05.08.13 07:34
Оценка: +1
Здравствуйте, okman, Вы писали:

O>В общем, можете посоветовать какой-нибудь интересный материальчик по теме ?

O>Только без Boost.PP — там разобраться может только маньяк.

Хм. Всегда считал BOOST.PP простой и удобной библиотекой. В код BOOST.PP не заглядывал, т.к. без надобности.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: Препроцессорные трюки.
От: zaufi Земля  
Дата: 05.08.13 09:45
Оценка:
Здравствуйте, okman, Вы писали:

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


Z>>или ты хочешь написать свой аналог??


O>Хотел бы научиться с помощью препроцессора преодолевать некоторые ограничения самого С++.

O>Как это делается в Boost.

повтыкай в tutorial, попробуй решить какую-нить свою "жизненную" задачу (например наделать шаблонных врапперов чего-либо с параметрами от 1 до MY_LIB_MAX_ARGS) -- этого вполне достаточно, чтобы покрыть большую часть необходимостей
Re[3]: Препроцессорные трюки.
От: pzhy  
Дата: 05.08.13 09:58
Оценка:
Здравствуйте, okman, Вы писали:

O>Хотел бы научиться с помощью препроцессора преодолевать некоторые ограничения самого С++.

O>Как это делается в Boost.

Boost.PP — не так сложен в использовании как это кажется. Для понимания как это работает — в еклипс цдт — есть возможность пошагового разбора вывода макросов — единственная киллер фича там, ИМХО.
Re[3]: Препроцессорные трюки.
От: Evgeny.Panasyuk Россия  
Дата: 05.08.13 14:42
Оценка:
Здравствуйте, okman, Вы писали:

EP>>у MSVC много багов в препроцессоре

O>Например ?

#include <iostream>
using namespace std;

int main(int argc,char *argv[])
{
    #define IGNORE_SECOND_E(x, _) x
    #define IGNORE_SECOND(x) IGNORE_SECOND_E(x)
    #define FIRST(x) x, DUMMY
    #define HEAD(sequence) IGNORE_SECOND(FIRST sequence)

    std::cout << HEAD((42)(11));
}

Такой код компилируется и запускается на GCC и Clang, но не компилируется на MSVC.
Если же взять BOOST_PP_SEQ_HEAD или BOOST_PP_SEQ_FOR_EACH — то такой код будет работать везде, так как уже содержит необходимые костыли.
Re: Препроцессорные трюки.
От: jazzer Россия Skype: enerjazzer
Дата: 05.08.13 14:49
Оценка: 1 (1) +1
Здравствуйте, okman, Вы писали:

O>Заглянул ради интереса в Boost, увидел такой макрос


Он тебе не нужен. Просто пользуйся.

O>В общем, можете посоветовать какой-нибудь интересный материальчик по теме ?


Доки Boost.PP.

O>Только без Boost.PP — там разобраться может только маньяк.


Тебе не надо разбираться в его потрохах. Просто пользуйся.


ЗЫ Тебе правда надо знать, как в Boost.PP объехали какую-нть кривизну MSVC6 или SunCC4 или еще какой-нть мамонтовой мути типа gcc 2.95? Нафига? Просто пользуйся, там простой и понятный интерфейс.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Препроцессорные трюки.
От: okman Беларусь https://searchinform.ru/
Дата: 05.08.13 15:11
Оценка:
Здравствуйте, jazzer, Вы писали:

J>ЗЫ Тебе правда надо знать, как в Boost.PP объехали какую-нть кривизну MSVC6 или SunCC4 или еще какой-нть мамонтовой мути типа gcc 2.95? Нафига? Просто пользуйся, там простой и понятный интерфейс.


Хочу научиться эффективно использовать препроцессор.
Не для того, чтобы лепить где попало, а чтобы обходить некоторые ограничения языка.
Например, хотелось бы иметь свой легковесный аналог Scope Exit, под один конкретный
компилятор и платформу (Visual C++). Сделал попытку написать нечто подобное — не вышло
(из-за ограничений, связанных с использованием локальных классов). Попытался "подсмотреть",
как сделано в Boost — увидел там монстрообразную конструкцию, которая расширяется в не
менее монстрообразный набор темплейтов.

Вопрос в том и состоит — где бы найти материал, в котором описывались бы типовые
препроцессорные "трюки". Чтобы освоить это без погружения с головой в исходники Boost.PP.
Re[3]: Препроцессорные трюки.
От: Evgeny.Panasyuk Россия  
Дата: 05.08.13 15:40
Оценка: 8 (1)
Здравствуйте, okman, Вы писали:


O>Например, хотелось бы иметь свой легковесный аналог Scope Exit, под один конкретный

O>компилятор и платформу (Visual C++).

Вот пример совсем простой реализации, без Boost и C++11:
#include <iostream>
using namespace std;

#define CONCAT2(x,y) x ## y
#define CONCAT(x,y) CONCAT2(x,y)

#define SCOPE_EXIT() \
struct CONCAT(scope_exit_name_, __LINE__) \
{ \
    ~CONCAT(scope_exit_name_, __LINE__)() \
/**/

#define SCOPE_EXIT_END } CONCAT(scope_exit_varname_, __LINE__) =

int main()
{
    int x = 11;
    SCOPE_EXIT()
        {
            cout << "scope exit: " << y << endl;
        }
        int &y;
    SCOPE_EXIT_END{x};
    cout << "body: " << x << endl;
    x = 42;
}


А вот пример реализации с использованием C++11 и stack_unwinding:
http://ideone.com/tyb14x
scope(exit)
{
    cout << "exit" << endl;
};
scope(success)
{
    cout << "success" << endl;
};
scope(failure)
{
    cout << "failure" << endl;
};


O>Сделал попытку написать нечто подобное — не вышло

O>(из-за ограничений, связанных с использованием локальных классов).

Каких ограничений?
Re[4]: Препроцессорные трюки.
От: FrozenHeart  
Дата: 05.08.13 21:07
Оценка:
EP>Каких ограничений?

Может быть, он об этом?
Re[3]: Препроцессорные трюки.
От: nen777w  
Дата: 05.08.13 21:59
Оценка: 1 (1) +1
Z>>или ты хочешь написать свой аналог??

O>Хотел бы научиться с помощью препроцессора преодолевать некоторые ограничения самого С++.

O>Как это делается в Boost.

boost::preprocessor уже заточен на массу компиляторов с их особенностями и кривулями.
Если тебе хочется "научиться с помощью препроцессора преодолевать некоторые ограничения самого С++" то тебе по сути прийдется нагородить массу макросов саомстоятельно что по сути равно, написать самому часть boost pp, возможно с багами, возможно с дальнейшим переписыванием внезапно под новый компилятор.
Отладка препроцессора не такая уж удобная штука.

Для развлечения, можно просто подсмотреть как реализованы те или инные части (я например так делал когда выполнял тестовое задание в ESET), но не более того.
В реальном проекте я просто беру библиотеки boost и благодарю тех ребят которые его поддерживают.
Re[5]: Препроцессорные трюки.
От: Evgeny.Panasyuk Россия  
Дата: 05.08.13 22:32
Оценка:
Здравствуйте, FrozenHeart, Вы писали:

EP>>Каких ограничений?

FH>Может быть, он об этом?

как это относится к обсуждаемому scope exit?
Re[6]: Препроцессорные трюки.
От: FrozenHeart  
Дата: 06.08.13 05:32
Оценка:
EP>как это относится к обсуждаемому scope exit?

Напрямую — не знаю. Может, у него реализация должна была использовать подобные возможности. Просто это единственное известное мне ограничение MSVC в данном плане.
Re[4]: Препроцессорные трюки.
От: jyuyjiyuijyu  
Дата: 09.08.13 21:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>А вот пример реализации с использованием C++11 и stack_unwinding:

EP>http://ideone.com/tyb14x
EP>
EP>scope(exit)
EP>{
EP>    cout << "exit" << endl;
EP>};
EP>scope(success)
EP>{
EP>    cout << "success" << endl;
EP>};
EP>scope(failure)
EP>{
EP>    cout << "failure" << endl;
EP>};
EP>



я правильно понимаю что scope(exit) выполнится при любом раскладе scope(success) если выход из скопа не вследствии исключения и scope(failure) вылетаем по исключению ? и еще почему такой ништяк не включат в boost ?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.