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

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

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.

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

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

You could

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

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

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

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 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    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.

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

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

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

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

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

.

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

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

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

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

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

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 года назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

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

    cin — stdin

    cerr — stderr

    cout — stdout

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

    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.

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

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

I see you're using a different template these days, is your current one doing the same work as this blog but with less code?