Препроцессор VC++ vs GCC

короче говоря, препроцессоры gcc и vc++ имеют разные выходные данные с одним и тем же входом. Похоже, что вариадические макросы в vc++ не делают "сопоставления аргументов" (если это правильный термин), если они переданы другим макросам. Например:

#define MACRO(a, ...)        head:a, tail:MACRO_OTHER(__VA_ARGS__)
#define MACRO_OTHER(a, ...)  head:a, tail:__VA_ARGS__

С

MACRO(1, 2, 3, 4, 5)

выход gcc:

head:1, tail:head:2, tail:3,4,5

на VC++ выход:

head:1, tail:head:2,3,4,5, tail:

видимо a на MACRO_OTHER и 2,3,4,5 С пустым разделом variadic arguments. Имея это в виду, есть ли способ создания альтернативы vc++ для следующего макроса (который отлично работает с gcc)

#define VA_TYPES_WITH_ARGS(...) __VA_TYPES_WITH_ARGS(VA_NUM_ARGS(__VA_ARGS__),##__VA_ARGS__)
#define __VA_TYPES_WITH_ARGS(n, ...) _VA_TYPES_WITH_ARGS(n,##__VA_ARGS__)
#define _VA_TYPES_WITH_ARGS(n, ...) _VA_TYPES_WITH_ARGS_##n(__VA_ARGS__)
#define _VA_TYPES_WITH_ARGS_0()
#define _VA_TYPES_WITH_ARGS_1(type     ) type _arg1
#define _VA_TYPES_WITH_ARGS_2(type, ...) type _arg2, _VA_TYPES_WITH_ARGS_1(__VA_ARGS__)
#define _VA_TYPES_WITH_ARGS_3(type, ...) type _arg3, _VA_TYPES_WITH_ARGS_2(__VA_ARGS__)
// etc

он в основном добавляет _argK для каждого аргумента.

пример:

VA_TYPES_WITH_ARGS(int, bool, float)

будет расширяться, чтобы

int _arg3, bool _arg2, float _arg1

любая помощь будет высоко оценили.


вопросы, связанные с препроцессора:

разница между gcc и препроцессором Microsoft

неожиданный Поведение препроцессора GCC и VC++

2 ответов


вы можете сделать это разумно кросс-компилятором (и принять еще много аргументов без дополнительной работы для загрузки), используя Boost, который, я могу сказать вам, потратив столько времени на просмотр заголовков, имеет много обходных путей для таких проблем, как эти:

#define VA_TYPES_WITH_ARGS(...)   \
    BOOST_PP_ENUM(                \
        BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),    \
        VA_TYPES_WITH_ARGS_MACRO,               \
        BOOST_PP_VARIADIC_TO_TUPLE(__VA_ARGS__) \
    )

#define VA_TYPES_WITH_ARGS_MACRO(z, n, data)       \
    BOOST_PP_TUPLE_ELEM(n, data) BOOST_PP_CAT(     \
        _arg,                                      \
        BOOST_PP_SUB(BOOST_PP_TUPLE_SIZE(data), n) \
    )                                              

VA_TYPES_WITH_ARGS(int, bool, float) //int _arg3 , bool _arg2 , float _arg1

первый макрос перебирает (ENUM) над аргументами variadic, вызывая второй для каждого и добавляя запятые соединения. Он формирует кортеж из вариационных данных, чтобы дать второму макрос.

второй формирует этот элемент (TUPLE_ELEM), затем _arg объедены (CAT) С size - n (SUB), где size - количество элементов в данных вариативную (с учетом макрос как кортеж) (TUPLE_SIZE).

смотрите, как это работает.


автономный подход, который работает для VC++ и разрывается с GCC, является:

#define EXPAND(...) __VA_ARGS__
#define LPAREN (
#define RPAREN )

теперь вместо использования макроса, как x(__VA_ARGS__), используйте его так:EXPAND(x LPAREN __VA_ARGS__ RPAREN).

это заставляет препроцессор VC++ сканировать аргументы позже, чем обычно.

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

обратите внимание, что там не может быть стандартным ответом на C++: вы полагаетесь на x() будучи вызовом макроса без аргументов. Это не так, как препроцессор работает в стандартном C++: if x - это вариативная макрос x() вызывает макрос с одним аргументом, и что единственный аргумент пуст. Кроме того, вы полагаетесь на возможность опустить переменные аргументы: стандартный C++ также не позволяет этого. Если макрос определен как #define FOO(x,...), ссылаясь на него как FOO(1) является недействительным. Как не может быть стандартного подхода, надеюсь это не проблема для вас, что различные подходы обязательно будут специфичны для компилятора.