tantam75's blog

By tantam75, history, 5 years ago, In English

Hi everyone.

This is my template for debugging in C++. I was inspired by Tourist's source code and modified it to my style. Here is it:

Template

To debug, just type: debug(x, y, z...). It requires C++ 11 or above.

It can work with:

  • Primitive data types: bool, int, long long, float, ...

  • std::pair, std::string

  • Collection types: std::vector, std::map, std::set, ...
  • Expressions

It also support multiple arguments.


How to use

Primitive data types:

bool a = true;
debug(a);

int b = 1;
float c = 2.5;
long long d = LLONG_MAX;
char e = 'e';
debug(a, b, c, d, e);

Output:
'[a] = [true]'
'[a, b, c, d, e] = [true, 1, 2.5, 9223372036854775807, 'e']'

std::pair and std::string:

pair<int, int> a = {1, 2};
pair<string, bool> b = {"abcd", false};
pair<char, float> c = {'x', 0.5};
string d = "This is a string";
pair<int, pair<int, int> > e = {1, {2, 3}};
debug(a, b, c, d, e);

Output:
'[a, b, c, d, e] = [{1, 2}, {"abcd", false}, {'x', 0.5}, "This is a string", {1, {2, 3}}]'

Note: You should only debug a pair of simple data types. For example, the debug won't work if one of pair's elements is collection type (std::vector, std::map, std::set...).


Collection types:

Basically, the debug works with collections types which you can iterate by for (auto i: a). So the debugger won't work with collection types like std::queue or std::stack.

vector<int> a = {1, 2, 3, 4};
set<int> b = {1, 2, 2, 3, 3, 4, 4, 5};
map<string, int> c;
c["string 1"] = 1;
c["string 2"] = 2;
debug(a, b, c);

unordered_map<string, int> d;
d["string 3"] = 3;
d["string 4"] = 4;
multiset<int> e = {5, 5, 4, 3, 1, 1, 2};
vector<vector<int> > f = {{1, 2, 3}};
debug(d, e, f);

Output:
'[a, b, c] = [{1, 2, 3, 4}, {1, 2, 3, 4, 5}, {{"string 1", 1}, {"string 2", 2}}]'
'[d, e, f] = [{{"string 4", 4}, {"string 3", 3}}, {1, 1, 2, 3, 4, 5, 5}, {{1, 2, 3}}]'

Note: I haven't tried the debug with other complex data types nested in collection types.


Expressions:
int a = 1;
int b = 2;
debug(a + b, a * b, a / b, a - b, a / (float)b, 2019, 2019 - 1);

Output:
'[a + b, a * b, a / b, a - b, a / (float)b, 2019, 2019 - 1] = [3, 2, 0, -1, 0.5, 2019, 2018]'


You can use the template and change it's style to what you want. Hope it would help you debug in C++ easier.

  • Vote: I like it
  • +39
  • Vote: I do not like it

| Write comment?
»
5 years ago, # |
  Vote: I like it 0 Vote: I do not like it

You could

replace this
with this
  • »
    »
    5 years ago, # ^ |
      Vote: I like it +1 Vote: I do not like it

    If we do it, the marcro to work with collection types won't work

»
5 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Auto comment: topic has been updated by tantam75 (previous revision, new revision, compare).

»
5 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Have you compared it with this template for debugging which is also based on a submission by tourist? If yes, then how does it compare?

  • »
    »
    5 years ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    Also, how is your template better than what tourist used?

    I can see how it is worse: in your #define it would be better to use a comma instead of a semicolon so that it is treated as one statement if it is not enclosed in braces for example as the body of a for loop.

»
5 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Does not work for vector :( And of course for arrays

»
4 years ago, # |
  Vote: I like it 0 Vote: I do not like it

amazing, i just learn c++ template, and then i find these good stuffs.

»
4 years ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

.

  • »
    »
    4 years ago, # ^ |
      Vote: I like it +3 Vote: I do not like it

    You can use snippets in vs code for this purpose... You can find this in settings gear icon...

»
4 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Doesn't work with arrays. How can I modify it to work with arrays?

  • »
    »
    4 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    The function template template <typename T, typename... V> void _print(T t, V... v) takes its arguments by value. Arrays cannot be copied and are instead treated as pointers. Pointers don't know the size of the underlying array and thus do not support std::begin and std::end. Range-based for-loops, however, require these two functions.

    To prevent the decay, _print should take its arguments by reference. You can either use lvalue references _print(T const& t, V const&... v), or forwarding references _print(T&& t, V&&... v). The latter is usually preferred, but here it doesn't make a difference. In both cases, you avoid the costly copying in the recursion.

»
4 years ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

The same thing can be achieved by overloading ostream for STL containers (this way nested structures work too). Also, you can come up with some pretty neat one liners using fold expressions and lambdas.

Spoiler

If you'd like a more generic reader-writer/debugger template (using SFINAE) for C++ STL, you can look at submissions by @Narut on CF.

»
4 years ago, # |
  Vote: I like it 0 Vote: I do not like it

This is super helpful Thanks! But can you tell me how to redirect the cerr output to a file.. I do it with the command freopen("error.txt", "w", stdout ) but for multiple variables, it's showing the output on the terminal

  • »
    »
    4 years ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    freopen("error.txt", "w", stderr);

    cin — stdin

    cerr — stderr

    cout — stdout

  • »
    »
    4 years ago, # ^ |
    Rev. 2   Vote: I like it 0 Vote: I do not like it

    run this in terminal: ./a.out > output.txt 2>error_stream.txt This will write standard output (from cout) to output.txt and error output (from cerr and clog) to error_stream.txt. Nothing will be printed on terminal. Here "a.out" is the binary/compiled programme. If you have changed that name then change the above command accordingly.

»
22 months ago, # |
Rev. 12   Vote: I like it 0 Vote: I do not like it

This is my template and debug will work for any complex structure.

#include <bits/stdc++.h>
using namespace std;
/******** Debug Code *******/
void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\'' << x << '\''; }
void __print(const char *x) { cerr << '\"' << x << '\"'; }
void __print(const string &x) { cerr << '\"' << x << '\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }
template <typename A>
void __print(const A &x);
template <typename A, typename B>
void __print(const pair<A, B> &p);
template <typename... A>
void __print(const tuple<A...> &t);
template <typename T>
void __print(stack<T> s);
template <typename T>
void __print(queue<T> q);
template <typename T, typename... U>
void __print(priority_queue<T, U...> q);
template <typename A>
void __print(const A &x) {
    bool first = true;
    cerr << '{';
    for (const auto &i : x) {
        cerr << (first ? "" : ","), __print(i);
        first = false;
    }
    cerr << '}';
}
template <typename A, typename B>
void __print(const pair<A, B> &p) {
    cerr << '(';
    __print(p.first);
    cerr << ',';
    __print(p.second);
    cerr << ')';
}
template <typename... A>
void __print(const tuple<A...> &t) {
    bool first = true;
    cerr << '(';
    apply([&first](const auto &...args) { ((cerr << (first ? "" : ","), __print(args), first = false), ...); }, t);
    cerr << ')';
}
template <typename T>
void __print(stack<T> s) {
    vector<T> debugVector;
    while (!s.empty()) {
        T t = s.top();
        debugVector.push_back(t);
        s.pop();
    }
    reverse(debugVector.begin(), debugVector.end());
    __print(debugVector);
}
template <typename T>
void __print(queue<T> q) {
    vector<T> debugVector;
    while (!q.empty()) {
        T t = q.front();
        debugVector.push_back(t);
        q.pop();
    }
    __print(debugVector);
}
template <typename T, typename... U>
void __print(priority_queue<T, U...> q) {
    vector<T> debugVector;
    while (!q.empty()) {
        T t = q.top();
        debugVector.push_back(t);
        q.pop();
    }
    __print(debugVector);
}
void _print() { cerr << "]\n"; }
template <typename Head, typename... Tail>
void _print(const Head &H, const Tail &...T) {
    __print(H);
    if (sizeof...(T))
        cerr << ", ";
    _print(T...);
}
#ifndef ONLINE_JUDGE
#define debug(...) cerr << "Line:" << __LINE__ << " [" << #__VA_ARGS__ << "] = ["; _print(__VA_ARGS__)
#else
#define debug(...)
#endif
  • »
    »
    3 months ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    This is very useful debugging template.

    it works for every builtin fuction and stl well.