简体   繁体   English

如何将可变参数宏的所有 arguments 连接成带引号的字符串?

[英]How to concatenate all of the arguments of a variadic macro into a quoted string?

How to concatenate all of the arguments of a variadic macro into a quoted string?如何将可变参数宏的所有 arguments 连接成带引号的字符串?

Below is a definition of non-variadic macro that concatenates 2 arguments into a quoted string:下面是非可变参数宏的定义,它将 2 arguments 连接成带引号的字符串:

#define TO_STRING(x) #x
#define CONCAT_STRINGIFY(x,y) TO_STRING(x##y)

Invoking this macro like this:像这样调用这个宏:

CONCAT_STRINGIFY(AAA,BBB)

...produces the following output: ...产生以下 output:

"AAABBB"

How to make the macro CONCAT_STRINGIFY(...) variadic, so that it accepts an arbitrary number of arguments?如何使宏CONCAT_STRINGIFY(...)可变,以便它接受任意数量的 arguments?

PS聚苯乙烯
The solution can use only the C or C++ Preprocessor and no 3rd party libraries该解决方案只能使用 C 或 C++ 预处理器,不能使用第 3 方库
BTW: I am not passing the preprocessor's output to a C/C++ compiler.顺便说一句:我没有将预处理器的 output 传递给 C/C++ 编译器。

Here is a general solution.这是一个通用的解决方案。 It works with up to 342 arguments, but can be exponentially expanded to work with more arguments by adding more EVALs.它最多可处理 342 个 arguments,但可以通过添加更多 EVAL 以指数方式扩展以处理更多 arguments。

#define EVAL1(...) __VA_ARGS__
#define EVAL2(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__))))
#define EVAL3(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__))))
#define EVAL4(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__))))
#define EVAL5(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__))))

#define EMPTY()

#define TUPLE_AT_1(a,b,...) b
#define CHECK(...) TUPLE_AT_1(__VA_ARGS__)
#define CAT_PROBE(...) ,CAT_END,

#define CAT_IND() CAT_
#define CAT_(x,a,...) CHECK(CAT_PROBE a,CAT_NEXT)(x,a,__VA_ARGS__)
#define CAT_NEXT(x,a,...) CAT_IND EMPTY()()(x##a,__VA_ARGS__)
#define CAT_END(x,a,...) #x

#define CAT(...) EVAL5(CAT_(,__VA_ARGS__,()))
CAT(a,b,c,d,e,f,g,h,i,j,k) // "abcdefghijk"

It uses macro recursion to concatenate all arguments, until an artificially appended "()" argument is reached.它使用宏递归连接所有 arguments,直到到达人为附加的“()”参数。 I've chosen "()" because it isn't pastable, and easy to detect.我选择了“()”,因为它不可粘贴且易于检测。

Since MSVC by default doesn't implement a standard conforming preprocessor, you'll need to enable the /Zc:preprocessor flag for the above code to work on MSVC.由于默认情况下 MSVC 未实现符合标准的预处理器,因此您需要为上述代码启用/Zc:preprocessor标志才能在 MSVC 上运行。

Edit:编辑:

If you don't care about a general solution, here is a nice and compact one with up to 16 arguments:如果您不关心通用解决方案,这里有一个漂亮而紧凑的解决方案,最多 16 个 arguments:

#define CAT_(a,b,c,d,e,f,g,i,j,k,l,m,n,o,p,...) a##b##c##d##e##f##g##i##j##k##l##m##n##o##p
#define CAT(...) CAT_(__VA_ARGS__,,,,,,,,,,,,,,,,,)
#define STR(...) #__VA_ARGS__
#define STRe(...) STR(__VA_ARGS__)
STRe(CAT(1,2)) // "12"
STRe(CAT(1,2,3,4,5,6,7)) // "1234567"

Two solutions .两种解决方案

1. 1.

Based on the usual COUNT pattern, which is described in the answer on the other question (in comments) from Jarod42:基于通常的 COUNT 模式,这在 Jarod42 的另一个问题(评论中)的答案中有所描述:

First, you define argument counting macros.首先,您定义参数计数宏。 You might add arbitrary number of arguments (up to compiler limit) to COUNT_N and numbers in the definition of COUNT .您可以将任意数量的 arguments(最多编译器限制)添加到COUNT_NCOUNT定义中的数字。 It'll have the numbers in decreasing order after __VA_ARGS__ , thus it returns the argument count:它将在__VA_ARGS__之后按降序排列数字,因此它返回参数计数:

#define COUNT_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...)    N
#define COUNT(...)   COUNT_N(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
// Warning: COUNT() return 1 (as COUNT(A)) :-/

Then you'll need the usual IDENTITY and APPLY definitions:然后你需要通常的IDENTITYAPPLY定义:

#define IDENTITY(N) N
#define APPLY(macro, ...) IDENTITY(macro(__VA_ARGS__))

Finaly, you add a dispatcher based on arg count.最后,您根据 arg count 添加一个调度程序。 Unfortunately, you have to create a case for each number of arguments;不幸的是,您必须为每个数字 arguments 创建一个案例; if you like, you might generate that code (yes, even with preprocessor, but in a distinct run):如果愿意,您可以生成该代码(是的,即使使用预处理器,但在不同的运行中):

#define CONCAT_STRINGIFY_DISPATCH(N) CONCAT_STRINGIFY ## N

#define TO_STRING(X) #X
#define CONCAT_STRINGIFY1(A) TO_STRING(A)
#define CONCAT_STRINGIFY2(A, B) TO_STRING(A ## B)
#define CONCAT_STRINGIFY3(A, B, C) TO_STRING(A ## B ## C)
#define CONCAT_STRINGIFY4(A, B, C, D) TO_STRING(A ## B ## C ## D)
// ...

#define CONCAT_STRINGIFY(...) IDENTITY(APPLY(CONCAT_STRINGIFY_DISPATCH, COUNT(__VA_ARGS__)))(__VA_ARGS__)

CONCAT_STRINGIFY(AAA, BBB, CCC)

Perhaps a little more 'hacky', but sorter solution is to concatenate many arguments and pass empty arguments as needed:也许有点“hacky”,但排序解决方案是连接许多 arguments 并根据需要传递空的 arguments:

#define TO_STRING(X) #X
#define CONCAT_STRINGIFY_4(A, B, C, D, ...) TO_STRING(A ## B ## C ## D)
#define CS(...) CONCAT_STRINGIFY_4(__VA_ARGS__,,,,)

This works for up to 4 args, you might add more as needed.这适用于最多 4 个参数,您可以根据需要添加更多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM