2

I'm using qt, gcc and c++11.

I'd like to have a debug function which works in this way:

int a = 1;
float b = 2.2;
QString c = "hello";

usage:

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

I could have used just a variadic template function to solve it, but i need to print the variable name as well.

for just 1 argument this macro works fine

#define VAR(var) qDebug() << #var << var;

So I was trying to use variadics macro to solve my issue with something like:

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

It works with 1 variable, but when I try with more it gives me "macro VAR passed 2 argumets, but takes just 1".

How can I solve that?

milbrandt
  • 1,438
  • 2
  • 15
  • 20
Moia
  • 2,216
  • 1
  • 12
  • 34
  • The examples you link to are different, they all "pass" `__VA_ARGS__` to a variadic function. You try to pass it to your single-argument macro. – Mat Mar 07 '18 at 14:29
  • Ok, but I could bypass my need of using the variable name? – Moia Mar 07 '18 at 14:31

4 Answers4

2

You are calling the macro VAR with two arguments since __VA_ARGS__ expands to the full comma separated list. But that macro just takes one argument.

What you could do is still implement this with a variadic template, but use the macro to forward variable name and value. Unfortunately it requires quite a lot of boilerplate to merge and split variadic macro arguments. I believe Boost has a library for expressing this easier, but I have never worked with it.

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

Output:

heyo: 5
whoo: 7.5
eyy: 2
s: hello
typ1232
  • 5,535
  • 6
  • 35
  • 51
  • Yes I did know something like that, I hoped there was a non-boilerplate solution though :\ – Moia Mar 07 '18 at 16:16
  • @Moia I'm afraid there is none for the exact interface you desire. Since you require the variable name, the macro machinery is needed. At the same time macros do not provide a convenient way to process variable length arguments. – typ1232 Mar 08 '18 at 14:50
  • I guess there's no other option too – Moia Mar 08 '18 at 15:07
1

Not sure how the macros work but for printing all arguments you could use a recursive variadic template.

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

This would allow you to use the VAR macro.

MaLarsson
  • 260
  • 3
  • 10
  • "I could have used just a variadic template function to solve it, but i need to print the variable name as well." – Moia Mar 07 '18 at 16:01
1

It seems to me that a possible way is mix a recursive template solution (as suggested by MaLarsson) with a macro to duplicate the argument and transform in string the name of the variable for first occurrence.

I mean... if you define a recursive template function foo() (with a not template ground case that only print the 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...);
 }

and a trivial function macro bar() as follows

#define bar(x)  #x, x

you can invoke foo() using bar() for every argument as follows

foo(bar(a), bar(b), bar(c), bar(d));

The following is a full working example

#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));
 }
max66
  • 65,235
  • 10
  • 71
  • 111
0

This will help you to achieve what you need. I am using variadic macros along with variadic template parameters to achieve this.This method will help you print variable's value along with it's name. This method is completely type independent and supports variable number of arguments. And can even display values of STL's nicely , given that you overload output operator for them

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

Sample use :

int main()
{
    string a;
    int b;
    double c;
    a="string here";
    b = 7;
    c= 3.14;
    show(a,b,c);
}

Output :

a = string here | b = 7 | c = 3.14 
parth_07
  • 1,322
  • 16
  • 22
  • What is clog function? – Moia Jul 27 '20 at 06:15
  • @Moia clog is similar to cout , difference being it writes to standard error stream instead of standard output . For debugging purposes I prefer standard error stream , thus used clog here . – parth_07 Jul 27 '20 at 06:18