制作打印所有变量名称和值的可变参数宏/方法
Make variadic macro / method which prints all variables names and values
现有宏在我的应用程序中获取可变数量的变量。
我想使用这个宏,以 name=value
格式打印这些变量。
这是一个小例子:
#define EXISTING_MACRO(...) < ??? >
int main()
int a = 0;
int b = 1;
int c = 2;
EXISTING_MACRO(a,b,c);
输出应该是:
a=0, b=1, c=2
我已经尝试通过从宏中调用可变参数模板函数来实现这一点,并且我确实成功地打印了变量值,但没有打印变量名称。 (#x
打印它们的地址,即使没有,它也可能只显示方法变量名,'f'
):
#define SHOW(a) std::cout << #a << "=" << (a)
template<typename TF>
void write_err_output(std::ostream& out, TF const& f) {
out << f << std::endl;
}
template<typename TF, typename ... TR>
void write_err_output(std::ostream& out, TF const& f, TR const& ... rest) {
out << SHOW(f) << " ";
write_err_output(out, rest...);
}
你不能用宏来做到这一点。您可以使用 stringification for a single variable (the do{
...}while(0)
is useful because of this).
#define MYPRINT(VarName) do{ \
std::cout << #VarName "=" << VarName << std::endl;} while(0)
然后使用MYPRINT(x)
;您可以考虑为 arities 1 到 19 定义 MYPRINT1
... MYPRINT19
(也许是自动的,通过一些脚本)。
如果使用最近的 GCC you might customize it for your purposes using MELT,但我认为这不值得付出努力(您将花费数周时间)。
您可能会考虑使用其他一些预处理器(例如 gpp)或一些简单的脚本(例如 awk
)预处理您的 C++ 代码
您可以通过一些技巧来完成此操作。该 hack 不是很可靠,但如果您将它用于调试目的,它应该是可以接受的。
想法是将整个可变宏参数字符串化,然后通过逗号标记化将标签序列分开。这要求可变参数的 none 包含一个逗号,如果它们都是变量名就会出现这种情况,但没有办法要求这一点,事实上下面建议的代码将很乐意接受表达式,如图所示.
#define SHOW(...) show(std::cout, #__VA_ARGS__, __VA_ARGS__)
template<typename H1>
std::ostream& show(std::ostream& out, const char* label, H1&& value) {
return out << label << "=" << std::forward<H1>(value) << '\n';
}
template<typename H1, typename ...T>
std::ostream& show(std::ostream& out, const char* label, H1&& value, T&&... rest) {
const char* pcomma = strchr(label, ',');
return show(out.write(label, pcomma - label) << "="
<< std::forward<H1>(value)
<< ',',
pcomma + 1,
std::forward<T>(rest)...);
}
(在 coliru 直播)
为简单起见并避免 std::string
,我使用了标准 C strchr
函数而不是 C++ 库函数。对任何被冒犯的人表示歉意。
现有宏在我的应用程序中获取可变数量的变量。
我想使用这个宏,以 name=value
格式打印这些变量。
这是一个小例子:
#define EXISTING_MACRO(...) < ??? >
int main()
int a = 0;
int b = 1;
int c = 2;
EXISTING_MACRO(a,b,c);
输出应该是:
a=0, b=1, c=2
我已经尝试通过从宏中调用可变参数模板函数来实现这一点,并且我确实成功地打印了变量值,但没有打印变量名称。 (#x
打印它们的地址,即使没有,它也可能只显示方法变量名,'f'
):
#define SHOW(a) std::cout << #a << "=" << (a)
template<typename TF>
void write_err_output(std::ostream& out, TF const& f) {
out << f << std::endl;
}
template<typename TF, typename ... TR>
void write_err_output(std::ostream& out, TF const& f, TR const& ... rest) {
out << SHOW(f) << " ";
write_err_output(out, rest...);
}
你不能用宏来做到这一点。您可以使用 stringification for a single variable (the do{
...}while(0)
is useful because of this).
#define MYPRINT(VarName) do{ \
std::cout << #VarName "=" << VarName << std::endl;} while(0)
然后使用MYPRINT(x)
;您可以考虑为 arities 1 到 19 定义 MYPRINT1
... MYPRINT19
(也许是自动的,通过一些脚本)。
如果使用最近的 GCC you might customize it for your purposes using MELT,但我认为这不值得付出努力(您将花费数周时间)。
您可能会考虑使用其他一些预处理器(例如 gpp)或一些简单的脚本(例如 awk
)预处理您的 C++ 代码
您可以通过一些技巧来完成此操作。该 hack 不是很可靠,但如果您将它用于调试目的,它应该是可以接受的。
想法是将整个可变宏参数字符串化,然后通过逗号标记化将标签序列分开。这要求可变参数的 none 包含一个逗号,如果它们都是变量名就会出现这种情况,但没有办法要求这一点,事实上下面建议的代码将很乐意接受表达式,如图所示.
#define SHOW(...) show(std::cout, #__VA_ARGS__, __VA_ARGS__)
template<typename H1>
std::ostream& show(std::ostream& out, const char* label, H1&& value) {
return out << label << "=" << std::forward<H1>(value) << '\n';
}
template<typename H1, typename ...T>
std::ostream& show(std::ostream& out, const char* label, H1&& value, T&&... rest) {
const char* pcomma = strchr(label, ',');
return show(out.write(label, pcomma - label) << "="
<< std::forward<H1>(value)
<< ',',
pcomma + 1,
std::forward<T>(rest)...);
}
(在 coliru 直播)
为简单起见并避免 std::string
,我使用了标准 C strchr
函数而不是 C++ 库函数。对任何被冒犯的人表示歉意。