For a single variable (or a given number of variables), it's easy to use macros to stringify variables. E.g. for 2 variables, I can do:
#define STRINGIFY(var1, var2) (std::string(#var1) + " " + #var2)
Is there a way to extend the above with either variadic macros or some other sort of compile-time trickery, to ultimately get a STRINGIFY
function that accepts an arbitrary number of arguments?
答案 0 :(得分:1)
Stringify [an]任意数量的变量?
是一个问题,并且:
如何...获取一个接受任意数量参数的STRINGIFY函数?
是另一个问题。猜测第一个问题是重要的问题 对你来说,这就足够了:
#define STRINGIFY(tokz) (std::string(#tokz))
一些无意义的用法:
<强>的main.cpp 强>
#include <iostream>
#define STRINGIFY(tokz) (std::string(#tokz))
#define FOO(x,y) \
{ int x = 1 ; int y = 2 ; std::string s = STRINGIFY(x y); \
cout << '[' << s << ']' << " -> " << x << ' ' << y << '\n'; \
}
#define BAR(x,y,z) \
{ char x = 'x'; char y = 'y'; char z = 'z'; \
std::string s = STRINGIFY([ x y z ]); \
cout << s << " -> " << x << ' ' << y << ' ' << z << '\n'; \
}
using namespace std;
int main()
{
cout << STRINGIFY(p q) << '\n' << STRINGIFY(r s t) << '\n';
FOO(a,b);
BAR(c,d,e);
return 0;
}
预处理:
$ g++ -E main.cpp | astyle
...
...
using namespace std;
int main()
{
cout << (std::string("p q")) << '\n' << (std::string("r s t")) << '\n';
{
int a = 1 ;
int b = 2 ;
std::string s = (std::string("a b"));
cout << '[' << s << ']' << " -> " << a << ' ' << b << '\n';
};
{
char c = 'x';
char d = 'y';
char e = 'z';
std::string s = (std::string("[ c d e ]"));
cout << s << " -> " << c << ' ' << d << ' ' << e << '\n';
};
return 0;
}
执行命令
$ g++ main.cpp && ./a.out
p q
r s t
[a b] -> 1 2
[ c d e ] -> x y z
答案 1 :(得分:1)
我不确定我是否明白你要做的事情。下面的代码在编译时标记__VA_ARGS__
。它不检查语法:它盲目地用'\0'
替换空格和逗号,将arg
中的标识符的开头和argc
中的参数的数量存储起来。
#include <iostream>
template < unsigned N > constexpr
unsigned countarg( const char( &s )[N], unsigned i = 0, unsigned c = 0 )
{
return
s[i] == '\0'
? i == 0
? 0
: c + 1
: s[i] == ','
? countarg( s, i + 1, c + 1 )
: countarg( s, i + 1, c );
}
template < unsigned N > constexpr
unsigned skipid( char( &s )[N], unsigned i = 0 )
{
return s[i] == '\0' || s[i] == ' ' || s[i] == '\t' || s[i] == ','
? i
: skipid( s, i + 1 );
}
template < unsigned N, unsigned M > constexpr
unsigned tokenize( char( &s )[N], const char*(&a)[M], unsigned i = 0, unsigned j = 0 )
{
return s[i] == '\0'
? i
: s[i] == ' ' || s[i] == '\t' || s[i] == ','
? ((s[i] = '\0'),
tokenize( s, a, ++i, j ))
: ((a[j] = s + i),
i = skipid( s, i ),
tokenize( s, a, i, ++j ));
}
#define TOKENIZEVA( ... ) char orig[] = #__VA_ARGS__; const unsigned argc = countarg(#__VA_ARGS__); const char* arg[argc]; tokenize( orig, arg );
#define PRINT( ... ) { TOKENIZEVA(__VA_ARGS__) for ( auto s : arg ) std::cout << s << std::endl; }
int main()
{
PRINT( first, second, third, fourth );
return 0;
}
答案 2 :(得分:0)
您无法在CPP中递归,但您可以#define
许多宏(DO1
,DO2
.. DO128
),然后使用一个“通用”宏,使用适当的后缀扩展为宏。
P99是一个lib(实际上是一个头文件),它提供了这样做的样板文件。 P99_SER
在每个参数上调用P99_STRINGIFY
之后粘贴用空格分隔的参数。
#include "p99_for.h"
P99_SER(P99_STRINGIFY, first,second,third,fourth,fifth,6)
扩展为
$ gcc -E test.c | tail -n 1
"first" "second" "third" "fourth" "fifth" "6"
答案 3 :(得分:0)
您可以使用以下内容(最多6个硬编码参数):
#define NARGS_(_1, _2, _3, _4, _5 , _6, N, ...) N
#define NARGS(args...) NARGS_(args..., 6, 5, 4, 3, 2, 1)
#define CAT_(a, b) a ## b
#define CAT(a, b) CAT_(a, b)
#define name_1(x) #x
#define name_2(x, x2) #x , #x2
#define name_3(x, x2, x3) #x , #x2, #x3
#define name_4(x, x2, x3, x4) #x , #x2, #x3, #x4
#define name_5(x, x2, x3, x4, x5) #x , #x2, #x3, #x4, #x5
#define name_6(x, x2, x3, x4, x5, x6) #x , #x2, #x3, #x4, #x5, #x6
#define names(args...) CAT(name_, NARGS(args))(args)
因此names(var1, var2)
会产生"var1", "var2"
。 (你可以传递给任何功能)
您还可以自定义name_x
。
答案 4 :(得分:0)
唉,你不能在预处理器中进行递归,但是你可以对这个可变参数宏的所有参数做一个&#34; apply宏。宏。
一个有用的想法是,在调用函数式宏时,()可以是参数的一部分。这可以让你做一些时髦的事情。在您的具体示例中......
首先,一个宏告诉我们__VA_ARGS__
包中有多少个参数:
#define NUM_ARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define NUM_ARGS(...) NUM_ARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
接下来,一个宏将一个给定的宏独立应用于__VA_ARGS__
包的每个元素:
#define FOREACH(MACRO, ...) FOREACH_(NUM_ARGS(__VA_ARGS__), MACRO, __VA_ARGS__)
#define FOREACH_(N, M, ...) FOREACH__(N, M, __VA_ARGS__)
#define FOREACH__(N, M, ...) FOREACH_##N(M, __VA_ARGS__)
#define FOREACH_1(M, A) M(A)
#define FOREACH_2(M, A, ...) M(A) FOREACH_1(M, __VA_ARGS__)
#define FOREACH_3(M, A, ...) M(A) FOREACH_2(M, __VA_ARGS__)
#define FOREACH_4(M, A, ...) M(A) FOREACH_3(M, __VA_ARGS__)
#define FOREACH_5(M, A, ...) M(A) FOREACH_4(M, __VA_ARGS__)
#define FOREACH_6(M, A, ...) M(A) FOREACH_5(M, __VA_ARGS__)
#define FOREACH_7(M, A, ...) M(A) FOREACH_6(M, __VA_ARGS__)
#define FOREACH_8(M, A, ...) M(A) FOREACH_7(M, __VA_ARGS__)
// Extend in the obvious way for as many iterations as needed.
一个简单的&#34;字符串化一个&#34;宏(确保其参数扩展):
#define STRINGIFY_(X) #X
#define STRINGIFY(X) STRINGIFY_(X)
现在让我们将所有部分组合在一起,制作一个构建字符串数组的好例子:
#define STRINGIFY_ALL(...) FOREACH(STRINGIFY, __VA_ARGS__)
#define COMMA(X) X,
#define COMMA_STRINGIFY(X) COMMA(STRINGIFY(X))
#define STRING_LITERAL_ARRAY(...) const char* STUFF[ NUM_ARGS(__VA_ARGS__) ] = { FOREACH(COMMA_STRINGIFY, __VA_ARGS__) };
STRING_LITERAL_ARRAY(I, AM, A, POTATO);
// Will yield:
const char* STUFF[ 4 ] { "I", "AM", "A", "POTATO" };
希望您能看到如何编写不同的&#34; lambda-like&#34;与FOREACH一起使用的宏可以做各种令人兴奋的事情。
答案 5 :(得分:-2)
尝试使用__VA_ARGS__
宏。
#include <stdio.h>
#define STRINGIFY(...) #__VA_ARGS__
int main()
{
int var1;
int var2;
int varN;
printf(STRINGIFY(var1 var2 varN)); // or STRINGIFY(var1, var2, varN)
return 0;
}
输出:
var1 var2 varN