如何在各个参数中拆分#__VA_ARGS__

How to split #__VA_ARGS__ in individual parameters

本文关键字:拆分 VA ARGS 参数      更新时间:2023-10-16

在可变宏中,#__VA_ARGS__是所有参数的逗号分隔字符串(至少我用gcc和clang得到了这种行为)。有没有一种方法可以在不解析字符串的情况下为各个参数创建一个字符串数组?

我正在使用下面的代码创建调试输出,如

DEBUG DUMP int main() AT demo.cc:53:
atan2(0.5, 0.5) => 0.785398
1 + 2 => 3
1 == 2 => false

来自等代码

debug_dump(atan2(0.5, 0.5), 1 + 2, 1 == 2);

但是,我目前的解决方案使用一个特殊的lexer来分割#__VA_ARGS__字符串,当然,它无法使用模板参数(如)解析复杂的情况

debug_dump(std::pair<int,int>().first, 0 < 1);

因为没有简单的方法来区分哪个CCD_ 3和/或CCD_。以下是我当前代码(需要C++11)的一个简短的自包含示例:

#include <utility>
#include <stdio.h>
#include <math.h>
void debug_dump_val_worker(int v) { fprintf(stderr, "%d", v); }
void debug_dump_val_worker(bool v) { fprintf(stderr, "%s", v ? "true" : "false"); }
void debug_dump_val_worker(double v) { fprintf(stderr, "%f", v); }
void debug_dump_args_worker(const char *) { }
template <typename T, typename ... Args>
void debug_dump_args_worker(const char *p, T first, Args ... args)
{
int next_p_state = 0;
const char *next_p = p;
while (*next_p && (next_p_state != 0 || *next_p != ',')) {
if (*next_p == '"')
do {
next_p++;
while (*next_p == '' && *(next_p + 1))
next_p += 2;
} while (*next_p && *next_p != '"');
if (*next_p == ''') {
next_p++;
if (*next_p == '')
next_p++;
if (*next_p)
next_p++;
}
if (*next_p == '(' || *next_p == '[' || *next_p == '{')
next_p_state++;
if ((*next_p == ')' || *next_p == ']' || *next_p == '}') && next_p_state > 0)
next_p_state--;
next_p++;
}
fprintf(stderr, "nt%.*s => ", int (next_p - p), p);
if (*next_p == ',')
next_p++;
while (*next_p == ' ' || *next_p == 't' || *next_p == 'r' || *next_p == 'n')
next_p++;
debug_dump_val_worker(first);
debug_dump_args_worker(next_p, args ...);
}
#define debug_dump(...) do { 
fprintf(stderr, "DEBUG DUMP %s AT %s:%d:", __PRETTY_FUNCTION__, __FILE__, __LINE__); 
debug_dump_args_worker(#__VA_ARGS__, __VA_ARGS__); 
fprintf(stderr, "n"); 
} while (0)
int main()
{
debug_dump(atan2(0.5, 0.5), 1 + 2, 1 == 2);
debug_dump(std::pair<int,int>().first, 0 < 1);
return 0;
}

Yakk说,预处理器不将<>视为匹配。

因此,如果你要这样做,那么你的代码需要比预处理器"更聪明"。一旦__VA_ARGS__被扩展到对debug_dump_args_worker的调用的参数中,就需要整个C++编译器来对其进行排序,并识别出有两个参数,而不是三个。在更复杂的情况下,>>旨在关闭两个模板参数列表,直到C++11,编译器才必须这样做,而不是将其视为一个不合时宜的移位运算符。因此,事实上,您的代码需要比C++03编译器"更聪明"(也就是说,您需要上下文敏感的标记化)。

我建议你最好的选择是放弃,并要求用户说:

debug_dump((std::pair<int,int>().first), 0 < 1);

相反。这是将模板参数转换为单个宏参数的"常用"方法。您至少可以通过检查从字符串中提取的表达式数量是否等于参数包的长度来捕捉错误。如果用户忘记在模板参数列表周围放置parens,那么您会发现字符串中有太多表达式。