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

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

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
  • Проголосовать: не нравится

»
5 лет назад, скрыть # |
 
Проголосовать: нравится 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

»
5 лет назад, скрыть # |
 
Проголосовать: нравится +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

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

I simply straight up copied tourist's debugging template

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

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

»
5 лет назад, скрыть # |
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

»
5 лет назад, скрыть # |
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
»
5 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

use fmtlib and wait for C++20

#include "fmt/core.h"

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

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

Debug Template
»
5 лет назад, скрыть # |
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!

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

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

»
5 лет назад, скрыть # |
 
Проголосовать: нравится +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!

»
5 лет назад, скрыть # |
 
Проголосовать: нравится +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.

»
3 года назад, скрыть # |
 
Проголосовать: нравится +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.