Пропустить препроцессор Boost, если переменная пуста

У меня есть следующий макрос препроцессора повышения для создания функции

extern "C" EXPORT out name(BOOST_PP_SEQ_FOR_EACH_I(PARAMETER_LIST, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)))

Это прекрасно работает, если только __VA_ARGS__ не пуст. После некоторых поисков я нашел способ подсчитать количество аргументов в __VA_ARGS__, используя BOOST_PP_VARIADIC_SIZE. Немного подумав, я написал этот МАКРОС:

extern "C" EXPORT out name(BOOST_PP_IF(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), BOOST_PP_SEQ_FOR_EACH_I(PARAMETER_LIST, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)), void))

Я думаю, что это должно сработать, однако я продолжаю получать следующее предупреждение

 warning C4002: too many actual parameters for macro 'BOOST_PP_IIF_1'

Хотя это предупреждение, похоже, что препроцессор ломается. При передаче нескольких аргументов будет обрабатываться только первый. Я нахожу это таким странным, как добавить это, если сломать все таким странным образом? Я проверил запятые и скобки сто раз, но они кажутся прекрасными. Как я могу исправить этот препроцессор?

http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/ref/if.html

Изменить: эта регрессия кажется актуальной: https://svn.boost.org/trac/boost/ticket/8606


person Roy T.    schedule 17.09.2013    source источник
comment
Выяснил причину, по которой ПЧ ломается. Аргументы для BOOST_PP_IF раскрываются до того, как BOOST_PP_IF оценивается. Это означает, что BOOST_PP_IF получает переменное количество аргументов, потому что один из его аргументов, который я передаю, расширяется до «x, y, z», к сожалению, я понятия не имею, как решить эту проблему сейчас.   -  person Roy T.    schedule 19.09.2013
comment
Это и, конечно же, директива препроцессора, ожидающая непустой VA_ARGS, по-прежнему вызывается всегда :(   -  person Roy T.    schedule 19.09.2013


Ответы (1)


выполнение:

#include <boost/preprocessor.hpp>

// based on the: http://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments
#define __ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define __HAS_COMMA(...) __ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define __TRIGGER_PARENTHESIS_(...) ,
#define __PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define __IS_EMPTY_CASE_0001 ,
#define __IS_EMPTY(_0, _1, _2, _3) __HAS_COMMA(__PASTE5(__IS_EMPTY_CASE_, _0, _1, _2, _3))

#define TUPLE_IS_EMPTY(...) \
    __IS_EMPTY( \
        /* test if there is just one argument, eventually an empty one */ \
        __HAS_COMMA(__VA_ARGS__), \
        /* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \
        __HAS_COMMA(__TRIGGER_PARENTHESIS_ __VA_ARGS__),                 \
        /* test if the argument together with a parenthesis adds a comma */ \
        __HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
        /* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \
        __HAS_COMMA(__TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) \
    )

#define __GEN_EMPTY_ARGS(...) \
    void

#define __GEN_NONEMPTY_ARGS_CB(unused, data, idx, elem) \
    BOOST_PP_COMMA_IF(idx) elem arg##idx

#define __GEN_NONEMPTY_ARGS(seq) \
    BOOST_PP_SEQ_FOR_EACH_I( \
         __GEN_NONEMPTY_ARGS_CB \
        ,~ \
        ,seq \
    )

#define GEN(out, name, ...) \
    extern "C" EXPORT out name( \
        BOOST_PP_IF( \
             TUPLE_IS_EMPTY(__VA_ARGS__) \
            ,__GEN_EMPTY_ARGS \
            ,__GEN_NONEMPTY_ARGS \
        )(BOOST_PP_TUPLE_TO_SEQ((__VA_ARGS__))) \
    ) {}

// test
GEN(void, finc0, int, char, long)
GEN(void, func1)

вывод:

extern "C" EXPORT void finc0( int arg0 , char arg1 , long arg2 ) {}
extern "C" EXPORT void func1( void ) {}
person niXman    schedule 28.10.2014
comment
Прошло некоторое время с тех пор, как я использовал этот код (более года назад). Но этот ответ кажется правильным решением. Спасибо! - person Roy T.; 29.10.2014
comment
Это вызывает предупреждения компилятора с более новым g++/clang++ (полное сообщение об ошибке здесь) main.cpp:49:1: warning: must specify at least one argument for '...' parameter of variadic macro [-Wgnu-zero-variadic-macro-arguments] C Стандарт ++ 11 (не уверен насчет C99) запрещает нулевые аргументы для вариативных макросов (stackoverflow.com/a/21266771/6490710) . Но у GNU CPP есть пара расширений, решающих эту проблему. Во-первых, вам разрешено полностью опускать переменный аргумент gcc.gnu.org/ onlinedocs/cpp/Variadic-Macros.html - person Jakob; 16.12.2016