使用可变参数宏打印多个调试行
print multiples debug lines with variadic macro
我正在使用 qt、gcc 和 c++11。
我想要一个以这种方式工作的调试功能:
int a = 1;
float b = 2.2;
QString c = "hello";
用法:
myFunc(a); // print a 1
myFunc(a, b); // print a 1 b 2.2
myFunc(a, b, c); // print a 1 b 2.2 c hello
我本可以只使用可变参数模板函数来解决它,但我还需要打印变量名。
这个宏只需要 1 个参数就可以正常工作
#define VAR(var) qDebug() << #var << var;
所以我尝试使用变量宏来解决我的问题,例如:
#define MVAR(...) VAR(__VA_ARGS__)
它适用于 1 个变量,但当我尝试使用更多变量时,它给了我 "macro VAR passed 2 argumets, but takes just 1"。
我该如何解决?
不确定宏是如何工作的,但要打印所有参数,您可以使用递归可变参数模板。
#include <iostream>
template <typename T>
void myFunc(T&& value) {
std::cout << value << '\n';
}
template <typename T, typename ...Ts>
void myFunc(T&& value, Ts&& ...rest) {
std::cout << value << '\n';
myFunc(std::forward<Ts>(rest)...);
}
int main() {
myFunc(0, 1, 2);
return 0;
}
这将允许您使用 VAR 宏。
您正在使用两个参数调用宏 VAR
,因为 __VA_ARGS__
扩展为完整的逗号分隔列表。但是那个宏只接受一个参数。
您可以做的仍然是使用可变参数模板来实现它,但使用宏来转发变量名称和值。不幸的是,它需要相当多的样板来合并和拆分可变参数宏参数。我相信 Boost 有一个库可以更轻松地表达这一点,但我从未使用过它。
#define EXPAND(x) x
#define COUNT_ARGS(...) COUNT_ARGS_(__VA_ARGS__, COUNT_ARGS_RSEQ())
#define COUNT_ARGS_(...) EXPAND(COUNT_ARGS_N(__VA_ARGS__))
#define COUNT_ARGS_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
#define COUNT_ARGS_RSEQ() 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define EXPAND_NAME_VALUE(argvalue, argname) argname, argvalue
#define EXPAND_ARGS(how, ...) EXPAND_ARGS_(how, COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
#define EXPAND_ARGS_(how, N, ...) EXPAND_ARGS__(how, N, __VA_ARGS__)
#define EXPAND_ARGS__(how, N, ...) EXPAND(EXPAND_ARGS_##N(how, __VA_ARGS__))
#define EXPAND_ARGS_1(how, arg, ...) how(arg, #arg)
#define EXPAND_ARGS_2(how, arg, ...) how(arg, #arg), EXPAND(EXPAND_ARGS_1(how, __VA_ARGS__))
#define EXPAND_ARGS_3(how, arg, ...) how(arg, #arg), EXPAND(EXPAND_ARGS_2(how, __VA_ARGS__))
#define EXPAND_ARGS_4(how, arg, ...) how(arg, #arg), EXPAND(EXPAND_ARGS_3(how, __VA_ARGS__))
// ...
#define MVAR(...) Print(EXPAND_ARGS(EXPAND_NAME_VALUE, __VA_ARGS__))
#include <string>
#include <iostream>
template <typename T>
void Print(const std::string& name, T&& value)
{
std::cout << name << ": " << value << "\n";
}
template <typename T, typename... Ts>
void Print(const std::string& name, T&& value, Ts&&... other)
{
Print(name, value);
Print(std::forward<Ts>(other)...);
}
int main()
{
int heyo = 5;
float whoo = 7.5;
double eyy = 2;
std::string s = "hello";
MVAR(heyo, whoo, eyy, s);
}
输出:
heyo: 5
whoo: 7.5
eyy: 2
s: hello
在我看来,一种可能的方法是将递归模板解决方案(如 MaLarsson 所建议的)与宏混合使用,以复制参数并在字符串中转换第一次出现的变量名称。
我的意思是......如果你定义一个递归模板函数foo()
(有一个非模板基础案例,只打印end-of-line)
void foo ()
{ std::cout << std::endl; }
template <typename A0, typename ... As>
void foo (char const * nameA0, A0 const & a0, As ... as)
{
std::cout << nameA0 << ' ' << a0 << ' ';
foo(as...);
}
和一个简单的函数宏bar()
如下
#define bar(x) #x, x
您可以使用 bar()
为每个参数调用 foo()
,如下所示
foo(bar(a), bar(b), bar(c), bar(d));
以下是完整的工作示例
#include <iostream>
void foo ()
{ std::cout << std::endl; }
template <typename A0, typename ... As>
void foo (char const * nameA0, A0 const & a0, As ... as)
{
std::cout << nameA0 << ' ' << a0 << ' ';
foo(as...);
}
#define bar(x) #x, x
int main()
{
int a { 0 };
std::string b { "one" };
foo(bar(a), bar(b));
}
这将帮助您实现所需。我正在使用可变参数宏和可变参数模板参数来实现 this.This 方法将帮助您打印变量的值及其名称。此方法完全独立于类型并支持可变数量的参数。甚至可以很好地显示 STL 的值,只要您为它们重载输出运算符
#define show(args...) describe(#args,args);
template<typename T>
void describe(string var_name,T value) //base case for template function
{
clog<<var_name<<" = "<<value<<" ";
}
template<typename T,typename... Args>
void describe(string var_names,T value,Args... args)
{
string::size_type pos = var_names.find(',');
string name = var_names.substr(0,pos);
var_names = var_names.substr(pos+1);
clog<<name<<" = "<<value<<" | ";
describe(var_names,args...);
}
示例使用:
int main()
{
string a;
int b;
double c;
a="string here";
b = 7;
c= 3.14;
show(a,b,c);
}
输出:
a = string here | b = 7 | c = 3.14
我正在使用 qt、gcc 和 c++11。
我想要一个以这种方式工作的调试功能:
int a = 1;
float b = 2.2;
QString c = "hello";
用法:
myFunc(a); // print a 1
myFunc(a, b); // print a 1 b 2.2
myFunc(a, b, c); // print a 1 b 2.2 c hello
我本可以只使用可变参数模板函数来解决它,但我还需要打印变量名。
这个宏只需要 1 个参数就可以正常工作
#define VAR(var) qDebug() << #var << var;
所以我尝试使用变量宏来解决我的问题,例如:
#define MVAR(...) VAR(__VA_ARGS__)
它适用于 1 个变量,但当我尝试使用更多变量时,它给了我 "macro VAR passed 2 argumets, but takes just 1"。
我该如何解决?
不确定宏是如何工作的,但要打印所有参数,您可以使用递归可变参数模板。
#include <iostream>
template <typename T>
void myFunc(T&& value) {
std::cout << value << '\n';
}
template <typename T, typename ...Ts>
void myFunc(T&& value, Ts&& ...rest) {
std::cout << value << '\n';
myFunc(std::forward<Ts>(rest)...);
}
int main() {
myFunc(0, 1, 2);
return 0;
}
这将允许您使用 VAR 宏。
您正在使用两个参数调用宏 VAR
,因为 __VA_ARGS__
扩展为完整的逗号分隔列表。但是那个宏只接受一个参数。
您可以做的仍然是使用可变参数模板来实现它,但使用宏来转发变量名称和值。不幸的是,它需要相当多的样板来合并和拆分可变参数宏参数。我相信 Boost 有一个库可以更轻松地表达这一点,但我从未使用过它。
#define EXPAND(x) x
#define COUNT_ARGS(...) COUNT_ARGS_(__VA_ARGS__, COUNT_ARGS_RSEQ())
#define COUNT_ARGS_(...) EXPAND(COUNT_ARGS_N(__VA_ARGS__))
#define COUNT_ARGS_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, N, ...) N
#define COUNT_ARGS_RSEQ() 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
#define EXPAND_NAME_VALUE(argvalue, argname) argname, argvalue
#define EXPAND_ARGS(how, ...) EXPAND_ARGS_(how, COUNT_ARGS(__VA_ARGS__), __VA_ARGS__)
#define EXPAND_ARGS_(how, N, ...) EXPAND_ARGS__(how, N, __VA_ARGS__)
#define EXPAND_ARGS__(how, N, ...) EXPAND(EXPAND_ARGS_##N(how, __VA_ARGS__))
#define EXPAND_ARGS_1(how, arg, ...) how(arg, #arg)
#define EXPAND_ARGS_2(how, arg, ...) how(arg, #arg), EXPAND(EXPAND_ARGS_1(how, __VA_ARGS__))
#define EXPAND_ARGS_3(how, arg, ...) how(arg, #arg), EXPAND(EXPAND_ARGS_2(how, __VA_ARGS__))
#define EXPAND_ARGS_4(how, arg, ...) how(arg, #arg), EXPAND(EXPAND_ARGS_3(how, __VA_ARGS__))
// ...
#define MVAR(...) Print(EXPAND_ARGS(EXPAND_NAME_VALUE, __VA_ARGS__))
#include <string>
#include <iostream>
template <typename T>
void Print(const std::string& name, T&& value)
{
std::cout << name << ": " << value << "\n";
}
template <typename T, typename... Ts>
void Print(const std::string& name, T&& value, Ts&&... other)
{
Print(name, value);
Print(std::forward<Ts>(other)...);
}
int main()
{
int heyo = 5;
float whoo = 7.5;
double eyy = 2;
std::string s = "hello";
MVAR(heyo, whoo, eyy, s);
}
输出:
heyo: 5
whoo: 7.5
eyy: 2
s: hello
在我看来,一种可能的方法是将递归模板解决方案(如 MaLarsson 所建议的)与宏混合使用,以复制参数并在字符串中转换第一次出现的变量名称。
我的意思是......如果你定义一个递归模板函数foo()
(有一个非模板基础案例,只打印end-of-line)
void foo ()
{ std::cout << std::endl; }
template <typename A0, typename ... As>
void foo (char const * nameA0, A0 const & a0, As ... as)
{
std::cout << nameA0 << ' ' << a0 << ' ';
foo(as...);
}
和一个简单的函数宏bar()
如下
#define bar(x) #x, x
您可以使用 bar()
为每个参数调用 foo()
,如下所示
foo(bar(a), bar(b), bar(c), bar(d));
以下是完整的工作示例
#include <iostream>
void foo ()
{ std::cout << std::endl; }
template <typename A0, typename ... As>
void foo (char const * nameA0, A0 const & a0, As ... as)
{
std::cout << nameA0 << ' ' << a0 << ' ';
foo(as...);
}
#define bar(x) #x, x
int main()
{
int a { 0 };
std::string b { "one" };
foo(bar(a), bar(b));
}
这将帮助您实现所需。我正在使用可变参数宏和可变参数模板参数来实现 this.This 方法将帮助您打印变量的值及其名称。此方法完全独立于类型并支持可变数量的参数。甚至可以很好地显示 STL 的值,只要您为它们重载输出运算符
#define show(args...) describe(#args,args);
template<typename T>
void describe(string var_name,T value) //base case for template function
{
clog<<var_name<<" = "<<value<<" ";
}
template<typename T,typename... Args>
void describe(string var_names,T value,Args... args)
{
string::size_type pos = var_names.find(',');
string name = var_names.substr(0,pos);
var_names = var_names.substr(pos+1);
clog<<name<<" = "<<value<<" | ";
describe(var_names,args...);
}
示例使用:
int main()
{
string a;
int b;
double c;
a="string here";
b = 7;
c= 3.14;
show(a,b,c);
}
输出:
a = string here | b = 7 | c = 3.14