Возьмем для примера следующий макрос:
#define _CREATE_VAR(X1) double X1{smc::define_variable (data, X1, #X1)};
#define _CREATE_VAR2(X1,X2) double X1{smc::define_variable (data, X1, #X1)}; /
double X2{smc::define_variable (data, X2, #X2)}; /
#define _CREATE_VAR3(X1,X2,X3) double X1{smc::define_variable (data, X1, #X1)}; /
double X2{smc::define_variable (data, X2, #X2)}; /
double X3{smc::define_variable (data, X3, #X3)}; /
#define _CREATE_VAR4(X1,X2,X3,X4) double X1{smc::define_variable (data, X1, #X1)}; /
double X2{smc::define_variable (data, X2, #X2)}; /
double X3{smc::define_variable (data, X3, #X3)}; /
double X4{smc::define_variable (data, X4, #X4)}; /
#define _CREATE_VAR5(X1,X2,X3,X4,X5) double X1{smc::define_variable (data, X1, #X1)}; /
double X2{smc::define_variable (data, X2, #X2)}; /
double X3{smc::define_variable (data, X3, #X3)}; /
double X4{smc::define_variable (data, X4, #X4)}; /
double X5{smc::define_variable (data, X5, #X5)}; /
Есть ли способ упростить это с помощью одного макроса _CREATE_VAR
вместо того, чтобы иметь несколько экземпляров с разными переменными аргументами и соответствующими именами? В идеале я бы хотел автоматически вызывать один и тот же макрос _CREATE_VAR
независимо от того, сколько аргументов.
Если вы не против немного другого синтаксиса вызова, вы можете использовать boost.preprocessor для этого:
#include "boost/preprocessor.hpp"
// or to not include entire preprocessor header, the following header files will do
// #include <boost/preprocessor/stringize.hpp>
// #include <boost/preprocessor/seq/for_each.hpp>
#define CREATE_ONE_VAR(maR_, maData_, maVarName) \
double maVarName {smc::define_variable (data, maVarName, BOOST_PP_STRINGIZE(maVarName))};
#define CREATE_VAR(maSeq) \
BOOST_PP_SEQ_FOR_EACH(CREATE_ONE_VAR, %%, maSeq)
Пример использования:
CREATE_VAR((x1)(x2)(x3)) //does the same as your original _CREATE_VAR3(x1, x2, x3)
Теперь вы можете вызывать его с любым количеством переменных от 1 до BOOST_PP_LIMIT_SEQ
, что обычно 256.
Несколько заметок:
я использую %%
чтобы указать, что аргумент не используется. Вы можете поместить туда что угодно (это передается внутреннему макросу maData
параметр, который мы не используем).
Вы не должны называть свои макросы, чтобы начать с подчеркивания, за которым следует заглавная буква. Это недопустимо в соответствии со стандартом, так как такие символы (а также любые символы, включая два последовательных подчеркивания) зарезервированы для вашего компилятора.
Один из способов сделать это — использовать FOR_EACH
макрос на __VA_ARGS__
, это не красиво, и, вероятно, требуется некоторое время, чтобы полностью понять, что происходит, но, по крайней мере, это не зависит от boost
,
Вспомогательные макросы:
// Concatenates tokens, even when the tokens are macros themselves.
#define PP_JOIN_HELPER_HELPER(_0, _1) _0##_1
#define PP_JOIN_HELPER(_0, _1) PP_JOIN_HELPER_HELPER(_0, _1)
#define PP_JOIN_IMPL(_0, _1) PP_JOIN_HELPER(_0, _1)
#define PP_JOIN_2(_0, _1) PP_JOIN_IMPL(_0, _1)
#define PP_JOIN_3(_0, _1, _2) PP_JOIN_2(PP_JOIN_2(_0, _1), _2)
#define PP_JOIN_4(_0, _1, _2, _3) PP_JOIN_2(PP_JOIN_3(_0, _1, _2), _3)
#define PP_JOIN_5(_0, _1, _2, _3, _4) PP_JOIN_2(PP_JOIN_4(_0, _1, _2, _3), _4)
#define PP_JOIN_6(_0, _1, _2, _3, _4, _5) PP_JOIN_2(PP_JOIN_5(_0, _1, _2, _3, _4), _5)
#define PP_JOIN_7(_0, _1, _2, _3, _4, _5, _6) PP_JOIN_2(PP_JOIN_6(_0, _1, _2, _3, _4, _5), _6)
#define PP_JOIN_8(_0, _1, _2, _3, _4, _5, _6, _7) PP_JOIN_2(PP_JOIN_7(_0, _1, _2, _3, _4, _5, _6), _7)
#define PP_JOIN_9(_0, _1, _2, _3, _4, _5, _6, _7, _8) PP_JOIN_2(PP_JOIN_8(_0, _1, _2, _3, _4, _5, _6, _7), _8)
#define PP_JOIN_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) PP_JOIN_2(PP_JOIN_9(_0, _1, _2, _3, _4, _5, _6, _7, _8), _9)
#define PP_JOIN_11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) PP_JOIN_2(PP_JOIN_10(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9), _10)
#define PP_JOIN_12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) PP_JOIN_2(PP_JOIN_11(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10), _11)
#define PP_JOIN_13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) PP_JOIN_2(PP_JOIN_12(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11), _12)
#define PP_JOIN_14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) PP_JOIN_2(PP_JOIN_13(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12), _13)
#define PP_JOIN_15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) PP_JOIN_2(PP_JOIN_14(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13), _14)
#define PP_JOIN_16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) PP_JOIN_2(PP_JOIN_15(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14), _15)
// Chooses a value based on a condition.
#define PP_IF_0(t, f) f
#define PP_IF_1(t, f) t
#define PP_IF(cond, t, f) PP_JOIN_2(PP_IF_, PP_TO_BOOL(cond))(t, f)
// Converts a condition into a boolean 0 (=false) or 1 (=true).
#define PP_TO_BOOL_0 0
#define PP_TO_BOOL_1 1
#define PP_TO_BOOL_2 1
#define PP_TO_BOOL_3 1
#define PP_TO_BOOL_4 1
#define PP_TO_BOOL_5 1
#define PP_TO_BOOL_6 1
#define PP_TO_BOOL_7 1
#define PP_TO_BOOL_8 1
#define PP_TO_BOOL_9 1
#define PP_TO_BOOL_10 1
#define PP_TO_BOOL_11 1
#define PP_TO_BOOL_12 1
#define PP_TO_BOOL_13 1
#define PP_TO_BOOL_14 1
#define PP_TO_BOOL_15 1
#define PP_TO_BOOL_16 1
#define PP_TO_BOOL(x) PP_JOIN_2(PP_TO_BOOL_, x)
// Returns 1 if the arguments to the variadic macro are separated by a comma, 0 otherwise.
#define PP_HAS_COMMA(...) PP_HAS_COMMA_EVAL(PP_HAS_COMMA_ARGS(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0))
#define PP_HAS_COMMA_EVAL(...) __VA_ARGS__
#define PP_HAS_COMMA_ARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, ...) _16
// Returns 1 if the argument list to the variadic macro is empty, 0 otherwise.
#define PP_IS_EMPTY(...) \
PP_HAS_COMMA \
( \
PP_JOIN_5 \
( \
PP_IS_EMPTY_CASE_, \
PP_HAS_COMMA(__VA_ARGS__), \
PP_HAS_COMMA(PP_IS_EMPTY_BRACKET_TEST __VA_ARGS__), \
PP_HAS_COMMA(__VA_ARGS__ (~)), \
PP_HAS_COMMA(PP_IS_EMPTY_BRACKET_TEST __VA_ARGS__ (~)) \
) \
)
#define PP_IS_EMPTY_CASE_0001 ,
#define PP_IS_EMPTY_BRACKET_TEST(...) ,
// Retrieve the number of arguments handed to a variable-argument macro.
#define PP_VA_NUM_ARGS_HELPER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
#define PP_VA_NUM_ARGS(...) PP_VA_NUM_ARGS_HELPER(__VA_ARGS__, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
// Correctly handles the case of 0 arguments.
#define PP_NUM_ARGS(...) PP_IF(PP_IS_EMPTY(__VA_ARGS__), 0, PP_VA_NUM_ARGS(__VA_ARGS__))
// Pass each variable in a VA_ARGS list to a macro.
#define PP_FE_0(action, X)
#define PP_FE_1(action, X) action(X)
#define PP_FE_2(action, X, ...) action(X)PP_FE_1(action, __VA_ARGS__)
#define PP_FE_3(action, X, ...) action(X)PP_FE_2(action, __VA_ARGS__)
#define PP_FE_4(action, X, ...) action(X)PP_FE_3(action, __VA_ARGS__)
#define PP_FE_5(action, X, ...) action(X)PP_FE_4(action, __VA_ARGS__)
#define PP_FE_6(action, X, ...) action(X)PP_FE_5(action, __VA_ARGS__)
#define PP_FE_7(action, X, ...) action(X)PP_FE_6(action, __VA_ARGS__)
#define PP_FE_8(action, X, ...) action(X)PP_FE_7(action, __VA_ARGS__)
#define PP_FE_9(action, X, ...) action(X)PP_FE_8(action, __VA_ARGS__)
#define PP_FE_10(action, X, ...) action(X)PP_FE_9(action, __VA_ARGS__)
#define PP_FE_11(action, X, ...) action(X)PP_FE_10(action, __VA_ARGS__)
#define PP_FE_12(action, X, ...) action(X)PP_FE_11(action, __VA_ARGS__)
#define PP_FE_13(action, X, ...) action(X)PP_FE_12(action, __VA_ARGS__)
#define PP_FE_14(action, X, ...) action(X)PP_FE_13(action, __VA_ARGS__)
#define PP_FE_15(action, X, ...) action(X)PP_FE_14(action, __VA_ARGS__)
#define PP_FE_16(action, X, ...) action(X)PP_FE_15(action, __VA_ARGS__)
#define PP_FOR_EACH(action, ...) PP_JOIN_2(PP_FE_, PP_NUM_ARGS(__VA_ARGS__))(action, __VA_ARGS__)
Определение для вашего макроса:
#define CREATE_VAR(var) double var{smc::define_variable(data, var, #var)};
#define CREATE_VARS(...) PP_FOR_EACH(CREATE_VAR, __VA_ARGS__)
Кроме того, вы можете или не можете использовать #pragma GCC system_header
в зависимости от того, с каким предупреждением вы компилируете lvl, чтобы избавиться от ISO C99 requires rest arguments to be used
, Вы могли бы использовать #pragma GCC diagnostic ignored "-pedantic-errors"
но видимо это прослушивается. Если вы используете msvc, вам придется выяснить предупреждение, чтобы отключить его самостоятельно.
Согласно моему пониманию вашего вопроса. Вы должны использовать многоточие (…). Я предлагаю вам пройти по следующей ссылке. Это полная помощь, чтобы понять.
http://msdn.microsoft.com/en-us/library/ms177415(v=vs.80).aspx
Они называются Variadic Macros. Макрос может быть объявлен так, чтобы принимать переменное число аргументов так же, как функция.
Синтаксис объявления аналогичен синтаксису функций с переменными числами: многоточие «…» используется для указания того, что необходимо передать один или несколько аргументов. Однако общие компиляторы также разрешают передавать нулевой аргумент такому макросу. Во время раскрытия макроса каждое появление специального идентификатора va_args в списке замены макросов заменяются переданные аргументы.
Например, способ C99, также поддерживаемый компилятором VC ++.
#define FOO(fmt, ...) print(fmt, ##__VA_ARGS__)
void print(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsprintf(str, fmt, args);
va_end(args);
printf("%s\n", str);
}
Это простой пример использования, чтобы показать, как использовать vardiac maco, а затем, как мы можем правильно использовать список аргументов переменной … без поиска дополнительной библиотеки!
Также посмотрите на