Блог пользователя rachitiitr

Автор rachitiitr, 3 года назад, По-английски

Hi Community,

It's been a while I wrote a blog post here.
You can follow more such tricks on —

How debug macros work?

Straight to the point, I have often used the debug macro which stringifies the variable names and their values.

#define deb(x) cout << #x << " " << x 
int ten = 10;
deb(ten); // prints "ten = 10"

This is often useful in debugging.

The Problem with this macro — its not scalable

However, when you have multiple variables to log, you end up with more deb2 and deb3 macros.

#define deb(x) cout << #x << " " << x 
#define deb2(x) cout << #x << " " << x << " "  << #y << " " << y 
#define deb3(x, y, z) cout << #x << " " << x << " "  << #y << " " << y << " "  << #z << " " << z 

This is not scalable.

Solution using a powerful macro

Here is the solution using variadic macros and fold expressions,

#define deb(...) logger(#__VA_ARGS__, __VA_ARGS__)
template<typename ...Args>
void logger(string vars, Args&&... values) {
    cout << vars << " = ";
    string delim = "";
    (..., (cout << delim << values, delim = ", "));
}

int xx = 3, yy = 10, xxyy = 103;
deb(xx); // prints "xx = 3"
deb(xx, yy, xxyy); // prints "xx, yy, xxyy = 3, 10, 103"

Hope this helps, this is going to my template for sure

  • Проголосовать: нравится
  • +139
  • Проголосовать: не нравится

»
3 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Bro, you can overload macro in c++ like this: __#define GET_MACRO6(_1,_2,_3,_4,_5,_6,NAME,...) NAME__ __define deb_1(a)__ __define deb_2(a,b)__ __define deb_3(a,b,c)__ __define deb_4(a,b,c,d)__ __define deb_5(a,b,c,d,e)__ __define deb_6(a,b,c,d,e,f)__ __define deb(...) GET_MACRO6(__VA_ARGS__,deb_6,deb_5,deb_4,deb_3,deb_2,deb_1)(__VA_ARGS__)__

my full debug code: https://github.com/Wgmlgz/Random-code/blob/main/Cp/template.cpp

  • »
    »
    3 года назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    The issue with this is readability. Parameter packs and variadic templates seem like the future and easy to read (when you know how they work).

»
3 года назад, # |
  Проголосовать: нравится +11 Проголосовать: не нравится

I use something like this

#define gg(...) [](const auto&...x){ char c='='; cerr<<#__VA_ARGS__<<" "; ((cerr<<exchange(c,',')<<" "<<x),...); cerr<<endl; }(__VA_ARGS__);

usage the same

»
3 года назад, # |
  Проголосовать: нравится +8 Проголосовать: не нравится

I simply straight up copied tourist's debugging template

»
3 года назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Thanks but you still have to comment it out before submitting. Maybe use cerr ?

»
3 года назад, # |
Rev. 3   Проголосовать: нравится +18 Проголосовать: не нравится

I did some research and searched for very good debugging techniques and templates. So this is what I felt is the best method for debugging, and this works for several stl containers including maps and even policy based data structures.

Here is the template:

myprettyprint.hpp

Now, you might be feel that this would make my default template a lot more scary and confusing. So a solution to that is to use the #ifndef ONLINE_JUDGE preprocessor directive, and include the debug template as a .hpp file.

main template

Results:

output

note: the myprettyprint.hpp should be placed in a directory so that it is in the search path when compiling.
in ubuntu, I placed it here: /usr/include/c++/9/myprettyprint.hpp. I hope this helps!

original source: link1, link2

  • »
    »
    3 года назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Thanks for this idea! I just want to know that where should I place this hpp file? Inside my compiler's folder (where "bits/stdc++.h" is placed?)

    • »
      »
      »
      3 года назад, # ^ |
        Проголосовать: нравится +1 Проголосовать: не нравится

      "bits/stdc++.h" if placed under ubuntu (/usr/include/x86_64-linux-gnu/c++/9/bits) and for arch linux (/usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits).

      You should put "headerfile.hpp" in the above directory and use it like this

      code
      • »
        »
        »
        »
        3 года назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Got it.

        One doubt though that #define dbg(...) what does this do? Do I need to have some other dbg macro defined above for it to work or is it self sufficient?

        • »
          »
          »
          »
          »
          3 года назад, # ^ |
          Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

          One doubt though that #define dbg(...) what does this do
          This will make every dbg(..) statemets an EMPTY line. So, you dont have to comment out every dbg(..) statement in your code before submitting it.✌️
          And it is self sufficient.

»
3 года назад, # |
Rev. 2   Проголосовать: нравится +3 Проголосовать: не нравится

I simply use one existing pretty print header file

Update: put this in your stdc++.h

#ifdef LOCAL
#include<pprint.hpp>
pprint::PrettyPrinter _printer(std::cerr);
#define de(...) _printer.compact(true).print('[', #__VA_ARGS__,"] =", __VA_ARGS__)
#define de2(...) _printer.compact(false).print('[', #__VA_ARGS__,"] =", __VA_ARGS__)
#endif

and put this in your source code:

#ifndef LOCAL // https://github.com/p-ranav/pprint
#define de(...)
#define de2(...)
#endif
  • »
    »
    3 года назад, # ^ |
    Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится

    I tried to compile and it threw several errors. Am I missing something?
    [edit] fixed : I was not using c++17

»
3 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

use fmtlib and wait for C++20

#include "fmt/core.h"

fmt::print("x={} y={} z={}\n", x, y, z);
»
3 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

This is what I use, It looks pretty lengthy and ugly but works like a charm for me.

Debug Template
»
3 года назад, # |
Rev. 3   Проголосовать: нравится +8 Проголосовать: не нравится

I think most of the solutions for debugging here are quite non-generic in nature. I used to have such a debug template too (albeit with variadic macros and lots of overloads for printing STL containers). Then I came across Narut's awesome template for debugging that uses SFINAE in a pretty clever way, and I tinkered with it slightly to make it work with my old pretty printing template, to get the following result:

Debugging template

Note: This would work only with C++17 and later (because of std::apply and if constexpr among others).

Some advantages:

  1. Doing debug(a, b, c) (or any number of parameters) pretty prints variables a, b, c of any sane type defined in the C++ standard or STL (sane as in something that makes sense to be printed). For instance, if it is a pair or an arbitrary tuple of printable types, or a container of printable types, it can be printed using this template, and is hence a printable type. No need to define printing functions for literally every single type. You can print stuff like vector<pair<string, vector<tuple<int, char>>>> with this template too.

  2. It prints the line numbers as well, and takes care of printing containers in separate lines. In terms of formatting, it gives you a nice coloured output too.

For those curious, here's the explanation of how it works.

Explanation

And, of course, it's always better to have this all neatly packed into a local header like debug.hpp which helps in keeping your submission clean!

»
3 года назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

May you suggest other resources for further reading regarding variadic macros and fold expressions. Thanks !

»
3 года назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Great article! I'd like to suggest the following:

  • print all variables to stderr to have only solution output in stdout (useful if you're using additional tooling to check your code)
  • run this code only in debug mode (e.g., you can log some expensive function calls)

I mostly covered these topics in my article, feel free to check it out!

»
3 года назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

I am getting the below warning and my code isn't running.

warning: fold-expressions only available with '-std=c++17' or '-std=gnu++17'
   54 | (..., (cout << delim << values, delim = ", "));

The standard for the CPP set is already c++17 in my vs code.

Please help me in setting this debug code as my template.

»
22 месяца назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится
#ifdef LOCAL
#include "/Library/debug/debug.h"
#define debug(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define debug(x...)
#endif

I'm putting all my ugly debugging code inside "debug.h" file and include it only if I'm compiling the file locally, and also calling the debug function from an online judge will print nothing.