【发布时间】:2013-12-19 10:22:40
【问题描述】:
在可变参数宏中,#__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);
但我当前的解决方案使用临时词法分析器拆分 #__VA_ARGS__ 字符串,这当然无法解析具有模板参数的复杂案例,例如
debug_dump(std::pair<int,int>().first, 0 < 1);
因为没有简单的方法可以区分哪个< 和/或> 是模板参数的括号,哪个是移位或比较操作的一部分。这是我当前代码的一个简短的独立示例(需要 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, "\n\t%.*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;
}
【问题讨论】:
-
就前任而言,
std::pair<int,int>是两个论点... -
感谢大家的快速回复。我将在
debug_dump_args_worker(const char*)中添加一个assert(*p == 0),以确保用户在这种情况下确实使用(...),正如@steve-jessop 所建议的那样。
标签: c++ c c++11 c-preprocessor