2015-01-13 6 views
2

У меня есть два макроса препроцессора «A» и «B», которые необходимо объединить в список инициализаторов. Например .:Объединение необязательных макросов для формирования списка

MyType obj = { A, B }; 

Однако А может быть пустым, одно значение, или список, и В может быть пустым или одно значение. Поэтому проблема заключается в том, как избежать вставки ненужной запятой, т. Е. Когда A или B пуст.

Так решение псевдо-CPP-код будет:

#if EMPTY(B) 
MyType obj = { A }; 
#else 
MyType obj = { A, B }; 
#endif 

Но как написать тест EMPTY(), что для #define A это правда, для #define A 1,2,3 это ложь? (Я ошибался со вспомогательными макросами, не получая ничего похожего на компиляцию ...)

Обратите внимание, что макросы исходят из внешнего механизма конфигурации, поэтому решение, ориентированное на CPP, похоже на естественное соответствие, а не неизбежное справедливый вопрос: «Почему вы делаете это с помощью макросов?»

+0

Я чувствую, что суть этого вопроса заключается в том, как проверить, является ли аргумент макроса пустым. Я не думаю, что это возможно, к сожалению. – tenfour

ответ

2

Использование Boost.Preprocessor:

#include <boost/preprocessor.hpp> 

#define A (a)(b) 
#define B (x)(y)(z) 

#define SAFE_ENUM(seq) \ 
    BOOST_PP_IIF(\ 
     BOOST_PP_IS_BEGIN_PARENS(seq), \ 
     BOOST_PP_SEQ_ENUM, \ 
     BOOST_PP_TUPLE_EAT(1) \ 
    )(seq) \ 
    /**/ 

MyType obj = { SAFE_ENUM(A B) }; 

степень косвенности требуется, поскольку Повышения последовательности не может быть пустым (что было бы, если оба A и B являются пустыми

** редактировать **

.

Использование Chaos.Preprocessor вместо:

#include <chaos/preprocessor/control/inline_unless.h> 
#include <chaos/preprocessor/detection/is_empty.h> 
#include <chaos/preprocessor/seq/enumerate.h> 

#define A a, b 
#define B x, y, z 

#define CONVERT(...) \ 
    CHAOS_PP_INLINE_UNLESS(CHAOS_PP_IS_EMPTY_NON_FUNCTION(__VA_ARGS__))(\ 
     (__VA_ARGS__) \ 
    ) \ 
    /**/ 

MyType obj = { 
    CHAOS_PP_SEQ_ENUMERATE(
     CONVERT(A) CONVERT(B) 
    ) 
}; 
+0

Это выглядит многообещающим! Но я думаю, что все еще требуется преобразование из начальных списков с разделителями-запятыми в эту форму корневого кортежа, т. Е. Как преобразовать из A «1, 2, 3» в «(1) (2) (3)»? BOOST_PP_ARRAY_TO_SEQ приближается, но требуется длина массива, например. преобразуется из "(3, (1,2,3))" –

+0

Зачем вам вводится ввод в форме '1, 2, 3'? Я спрашиваю, потому что эта форма вызовет проблемы с шаблонами с несколькими параметрами шаблона. Например. в 'std :: pair ' запятая будет вмешиваться.Кроме того, какой компилятор вы используете? –

+0

Просто потому, что я предпочел бы не вводить дополнительный шаг перехода между существующим механизмом настройки и компиляцией - если это необходимо, то этот шаг может просто вставить всю эту логическую конструкцию с дополнительным списком. Это компиляция с clang_3.5 и gcc_4.8.1. –

2

Невозможно проверить, определен ли макрос, но пуст во время компиляции. Предкомпилятор позволяет сравнивать целые числа, т.е.

#if A > 5 

но не строки:

#if A == "" // Not allowed! 

И нет, конечно, нет поддержки списков. Я бы сказал, что самый простой способ сделать это, чтобы создать список Инициализатора для каждого макроса, а затем объединить их во время выполнения, как:

MyType objA = { A }; 
MyType objB = { B }; 
// ... now combine them ... 

Естественно, это очень упрощенно и сильно зависит от ваших макросов, но при условии что они гарантированно будут действительными списками, это должно сработать.

+0

Спасибо - я боялся, что не было решения «входной двери» - к сожалению, комбинация времени исполнения выглядит неудобно, так как реальный тип - это «constexpr std :: array». Пока что запятая кажется неудобной частью при попытках с конструктивными аргументами-аргументами и шаблонами - кроме массивов и переписных запятых, являются плохими новостями. Все еще надеясь, что какой-то злой (препроцессор) гений предложит «план, настолько безумный, что он может просто работать» –

Смежные вопросы