print使用可变参数宏对调试行进行多次打印

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了print使用可变参数宏对调试行进行多次打印相关的知识,希望对你有一定的参考价值。

我正在使用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;

所以我试图使用variadics宏来解决我的问题,例如:

#define MVAR(...) VAR(__VA_ARGS__)

它适用于1个变量,但是当我尝试更多它时,它给了我“宏VAR传递2个争论,但只需1个”。

我怎么解决这个问题?

答案

由于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 << "
";
}
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
另一答案

不确定宏是如何工作的,但是对于打印所有参数,您可以使用递归可变参数模板。

#include <iostream>

template <typename T>
void myFunc(T&& value) {
    std::cout << value << '
';
}

template <typename T, typename ...Ts>
void myFunc(T&& value, Ts&& ...rest) {
    std::cout << value << '
';
    myFunc(std::forward<Ts>(rest)...);
}

int main() {
    myFunc(0, 1, 2);
    return 0;
}

这将允许您使用VAR宏。

另一答案

在我看来,一种可能的方法是将递归模板解决方案(如MaLarsson所建议)与宏混合以复制参数,并在字符串中转换第一次出现的变量的名称。

我的意思是...如果你定义一个递归模板函数foo()(带有非模板地面案例,只打印行尾)

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

您可以使用foo()为每个参数调用bar(),如下所示

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));
 }

以上是关于print使用可变参数宏对调试行进行多次打印的主要内容,如果未能解决你的问题,请参考以下文章

可变参数宏(DEBUG)

是否可以迭代可变参数宏中的参数?

可变参数编程

C语言可变参数

用于打印可变参数的宏,可以选择无参数

用于打印可变参数的宏,可选择无参数