C++ C++;和预处理器宏:可变类型
以以下宏为例:C++ C++;和预处理器宏:可变类型,c++,macros,variadic,preprocessor-directive,C++,Macros,Variadic,Preprocessor Directive,以以下宏为例: #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
#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)}; /
有没有办法通过使用一个宏
\u CREATE\u VAR
而不是使用多个具有不同变量参数和相应名称的实例来简化此过程?理想情况下,我希望自动调用同一个宏\u CREATE\u VAR
,而不管有多少个参数。这些被称为可变宏,宏可以声明为像函数一样接受可变数量的参数
声明语法类似于可变函数:省略号“…”用于指示必须传递一个或多个参数。然而,普通编译器也允许向这样的宏传递零参数。在宏展开过程中,宏替换列表中出现的每个特殊标识符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,以及如何正确使用变量参数列表…而不需要寻找其他库
也看看
根据我对你问题的理解。您应该使用省略号(…)。我建议你通过下面的链接。这对理解完全有帮助
如果您不介意稍有不同的调用语法,您可以使用:
#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)
现在,您可以使用从1到BOOST\u PP\u LIMIT\u SEQ
的任意数量的变量调用它,通常为256
请注意:
我使用%%
表示参数未使用。您可以将任何内容放入其中(它被传递到内部宏的maData
参数,我们不使用该参数)
您不应该将宏命名为以下划线和大写字母开头。根据标准,这是非法的,因为这样的符号(以及任何包含两个连续下划线的符号)都是为编译器保留的。一种方法是在
\uu VA\u ARGS\uu
上为每个宏使用,它并不漂亮,可能需要一段时间才能完全了解发生了什么,但至少它不依赖于boost
#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);
}
辅助宏:
// 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_头
,这取决于编译时使用的警告级别,以摆脱ISO C99要求使用rest参数
。您可以使用#pragma GCC diagnostic ignored“-pedantic errors”
,但显然。如果您使用的是msvc,您必须自己找出要禁用的警告。IMO,这只是部分答案。如何使用\uu VA\u ARGS\uuu
分别处理每个参数?有不同的方法使用它,看一看,我的错误我错过了好吧,这仍然只是将所有可变参数作为序列传递到其他地方(到可变C函数)。如何使用变量宏创建一个C++声明来为每个参数传递?你有机会查看吗?你有一个变量宏,但现在它取决于一个人如何使用,例如,我可以使用一个变量C函数,它使用这个参数列表。。。printf只是一个例子,展示了一些人如何从中受益……是的,我做到了。OP希望使用宏为宏的每个参数定义一个double
变量。你是如何使用variadics的?请注意,问题不是“如何编写可变宏?”,而是“如何只有一个宏来解决我的特定问题?”在我看来,这只是部分答案。如何使用\uu VA\u ARGS\uu
分别处理每个参数?数据
变量是什么,它来自哪里?数据
来自结构数据类型,对象名恰好被称为数据
atm<代码>数据
就是存储变量信息的地方。此信息单独存储,因为我需要许多实例,并且不需要复制数据的部分。最重要的是,Xi的
成为了我可以在另一个类中使用的对象,我可以在这个类中进行数值计算。我需要对象,因为我的每个使用这些变量的类都有不同的变化,其他用户也会使用这个接口。代码不错。这是你自己做的吗?我不知道;我还不知道我的代码是否会是boost-independent-atm,但如果会,这肯定会派上用场。很抱歉,我不能接受这个答案,目前@angew排在第一位,它又短又甜——目前适合我。谢谢你给我和其他人的选择。非常感谢。@woosah它主要是我在上面找到的一段代码的清理版本。我个人更喜欢免费的。您只需创建一个文件pp.h
,并将其包含在需要为每个和加入宏帮助程序的文件中。如果可能,最好不要依赖外部库。@woosah感谢您的编辑;在我有机会查看它之前,它被拒绝了,所以我已经手动重新添加了您的更改。不用担心,我不知道宏不能有一个预下划线。我一直认为这是双下划线。啊,好吧,你每天都能学到新东西!现在有点晚了,但是通过使用BOOST\u PP\u VARIADIC\u to_SEQ
,可以很容易地保留原始调用语法。不过,它可能只是C++11。我不确定Boost在这方面是否有什么诀窍。