C++ Debug Template 🛠
Simplify variable tracking across functions and loops!
Longer Template (std >= C++11)#ifndef DEBUG_TEMPLATE_CPP
#define DEBUG_TEMPLATE_CPP
#include <bits/stdc++.h>
// #define cerr cout
namespace __DEBUG_UTIL__
{
using namespace std;
/* Primitive Datatypes Print */
void print(const char *x) { cerr << x; }
void print(bool x) { cerr << (x ? "T" : "F"); }
void print(char x) { cerr << '\'' << x << '\''; }
void print(signed short int x) { cerr << x; }
void print(unsigned short int x) { cerr << x; }
void print(signed int x) { cerr << x; }
void print(unsigned int x) { cerr << x; }
void print(signed long int x) { cerr << x; }
void print(unsigned long int x) { cerr << x; }
void print(signed long long int x) { cerr << x; }
void print(unsigned long long int x) { cerr << x; }
void print(float x) { cerr << x; }
void print(double x) { cerr << x; }
void print(long double x) { cerr << x; }
void print(string x) { cerr << '\"' << x << '\"'; }
template <size_t N>
void print(bitset<N> x) { cerr << x; }
void print(vector<bool> v)
{ /* Overloaded this because stl optimizes vector<bool> by using
_Bit_reference instead of bool to conserve space. */
int f = 0;
cerr << '{';
for (auto &&i : v)
cerr << (f++ ? "," : "") << (i ? "T" : "F");
cerr << "}";
}
/* Templates Declarations to support nested datatypes */
template <typename T>
void print(T &&x);
template <typename T>
void print(vector<vector<T>> mat);
template <typename T, size_t N, size_t M>
void print(T (&mat)[N][M]);
template <typename F, typename S>
void print(pair<F, S> x);
template <typename T, size_t N>
struct Tuple;
template <typename T>
struct Tuple<T, 1>;
template <typename... Args>
void print(tuple<Args...> t);
template <typename... T>
void print(priority_queue<T...> pq);
template <typename T>
void print(stack<T> st);
template <typename T>
void print(queue<T> q);
/* Template Datatypes Definitions */
template <typename T>
void print(T &&x)
{
/* This works for every container that supports range-based loop
i.e. vector, set, map, oset, omap, dequeue */
int f = 0;
cerr << '{';
for (auto &&i : x)
cerr << (f++ ? "," : ""), print(i);
cerr << "}";
}
template <typename T>
void print(vector<vector<T>> mat)
{
int f = 0;
cerr << "\n~~~~~\n";
for (auto &&i : mat)
{
cerr << setw(2) << left << f++, print(i), cerr << "\n";
}
cerr << "~~~~~\n";
}
template <typename T, size_t N, size_t M>
void print(T (&mat)[N][M])
{
int f = 0;
cerr << "\n~~~~~\n";
for (auto &&i : mat)
{
cerr << setw(2) << left << f++, print(i), cerr << "\n";
}
cerr << "~~~~~\n";
}
template <typename F, typename S>
void print(pair<F, S> x)
{
cerr << '(';
print(x.first);
cerr << ',';
print(x.second);
cerr << ')';
}
template <typename T, size_t N>
struct Tuple
{
static void printTuple(T t)
{
Tuple<T, N - 1>::printTuple(t);
cerr << ",", print(get<N - 1>(t));
}
};
template <typename T>
struct Tuple<T, 1>
{
static void printTuple(T t) { print(get<0>(t)); }
};
template <typename... Args>
void print(tuple<Args...> t)
{
cerr << "(";
Tuple<decltype(t), sizeof...(Args)>::printTuple(t);
cerr << ")";
}
template <typename... T>
void print(priority_queue<T...> pq)
{
int f = 0;
cerr << '{';
while (!pq.empty())
cerr << (f++ ? "," : ""), print(pq.top()), pq.pop();
cerr << "}";
}
template <typename T>
void print(stack<T> st)
{
int f = 0;
cerr << '{';
while (!st.empty())
cerr << (f++ ? "," : ""), print(st.top()), st.pop();
cerr << "}";
}
template <typename T>
void print(queue<T> q)
{
int f = 0;
cerr << '{';
while (!q.empty())
cerr << (f++ ? "," : ""), print(q.front()), q.pop();
cerr << "}";
}
/* Printer functions */
void printer(const char *) {} /* Base Recursive */
template <typename T, typename... V>
void printer(const char *names, T &&head, V &&...tail)
{
/* Using && to capture both lvalues and rvalues */
int i = 0;
for (size_t bracket = 0; names[i] != '\0' and (names[i] != ',' or bracket != 0); i++)
if (names[i] == '(' or names[i] == '<' or names[i] == '{')
bracket++;
else if (names[i] == ')' or names[i] == '>' or names[i] == '}')
bracket--;
cerr.write(names, i) << " = ";
print(head);
if (sizeof...(tail))
cerr << " ||", printer(names + i + 1, tail...);
else
cerr << "]\n";
}
/* PrinterArr */
void printerArr(const char *) {} /* Base Recursive */
template <typename T, typename... V>
void printerArr(const char *names, T arr[], size_t N, V... tail)
{
size_t ind = 0;
for (; names[ind] and names[ind] != ','; ind++)
cerr << names[ind];
for (ind++; names[ind] and names[ind] != ','; ind++)
;
cerr << " = {";
for (size_t i = 0; i < N; i++)
cerr << (i ? "," : ""), print(arr[i]);
cerr << "}";
if (sizeof...(tail))
cerr << " ||", printerArr(names + ind + 1, tail...);
else
cerr << "]\n";
}
}
#ifndef ONLINE_JUDGE
#define debug(...) std::cerr << __LINE__ << ": [", __DEBUG_UTIL__::printer(#__VA_ARGS__, __VA_ARGS__)
#define debugArr(...) std::cerr << __LINE__ << ": [", __DEBUG_UTIL__::printerArr(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...)
#define debugArr(...)
#endif
#endif
Shorter Template, (std >= C++20)#ifndef DEBUG_TEMPLATE_CPP
#define DEBUG_TEMPLATE_CPP
#include <bits/stdc++.h>
// #define cerr cout
namespace __DEBUG_UTIL__
{
using namespace std;
template <typename T>
concept is_iterable = requires(T &&x) { begin(x); } &&
!is_same_v<remove_cvref_t<T>, string>;
void print(const char *x) { cerr << x; }
void print(char x) { cerr << "\'" << x << "\'"; }
void print(bool x) { cerr << (x ? "T" : "F"); }
void print(string x) { cerr << "\"" << x << "\""; }
void print(vector<bool> &v)
{ /* Overloaded this because stl optimizes vector<bool> by using
_Bit_reference instead of bool to conserve space. */
int f = 0;
cerr << '{';
for (auto &&i : v)
cerr << (f++ ? "," : "") << (i ? "T" : "F");
cerr << "}";
}
template <typename T>
void print(T &&x)
{
if constexpr (is_iterable<T>)
if (size(x) && is_iterable<decltype(*(begin(x)))>)
{ /* Iterable inside Iterable */
int f = 0;
cerr << "\n~~~~~\n";
for (auto &&i : x)
{
cerr << setw(2) << left << f++, print(i), cerr << "\n";
}
cerr << "~~~~~\n";
}
else
{ /* Normal Iterable */
int f = 0;
cerr << "{";
for (auto &&i : x)
cerr << (f++ ? "," : ""), print(i);
cerr << "}";
}
else if constexpr (requires { x.pop(); }) /* Stacks, Priority Queues, Queues */
{
auto temp = x;
int f = 0;
cerr << "{";
if constexpr (requires { x.top(); })
while (!temp.empty())
cerr << (f++ ? "," : ""), print(temp.top()), temp.pop();
else
while (!temp.empty())
cerr << (f++ ? "," : ""), print(temp.front()), temp.pop();
cerr << "}";
}
else if constexpr (requires { x.first; x.second; }) /* Pair */
{
cerr << '(', print(x.first), cerr << ',', print(x.second), cerr << ')';
}
else if constexpr (requires { get<0>(x); }) /* Tuple */
{
int f = 0;
cerr << '(', apply([&f](auto... args)
{ ((cerr << (f++ ? "," : ""), print(args)), ...); },
x);
cerr << ')';
}
else
cerr << x;
}
template <typename T, typename... V>
void printer(const char *names, T &&head, V &&...tail)
{
int i = 0;
for (size_t bracket = 0; names[i] != '\0' and (names[i] != ',' or bracket != 0); i++)
if (names[i] == '(' or names[i] == '<' or names[i] == '{')
bracket++;
else if (names[i] == ')' or names[i] == '>' or names[i] == '}')
bracket--;
cerr.write(names, i) << " = ";
print(head);
if constexpr (sizeof...(tail))
cerr << " ||", printer(names + i + 1, tail...);
else
cerr << "]\n";
}
template <typename T, typename... V>
void printerArr(const char *names, T arr[], size_t N, V... tail)
{
size_t i = 0;
for (; names[i] and names[i] != ','; i++)
cerr << names[i];
for (i++; names[i] and names[i] != ','; i++)
;
cerr << " = {";
for (size_t ind = 0; ind < N; ind++)
cerr << (ind ? "," : ""), print(arr[ind]);
cerr << "}";
if constexpr (sizeof...(tail))
cerr << " ||", printerArr(names + i + 1, tail...);
else
cerr << "]\n";
}
}
#ifndef ONLINE_JUDGE
#define debug(...) std::cerr << __LINE__ << ": [", __DEBUG_UTIL__::printer(#__VA_ARGS__, __VA_ARGS__)
#define debugArr(...) std::cerr << __LINE__ << ": [", __DEBUG_UTIL__::printerArr(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...)
#define debugArr(...)
#endif
#endif
As of now both perform equally well, but my choice? C++20.
Simple Usageint mat[3][5]{};
vector<int> v;
for (int i = 1; i <= 3; i++)
{
v.push_back(i * i);
debug(i, v);
}
debug(mat);
// stderr
23: [i = 1 || v = {1}]
23: [i = 2 || v = {1,4}]
23: [i = 3 || v = {1,4,9}]
25: [mat =
~~~~~
0 {0,0,0,0,0}
1 {0,0,0,0,0}
2 {0,0,0,0,0}
~~~~~
]
This template supports datatypes such as:
🔢 Primitive: int, char, bool, long long int
etc.
📚 STL: pair, tuple, vector, set, oset, map, omap, stack, queue, priority_queue, bitset
etc.
📦 Arrays of all datatypes: int arr[], bool arr[], vector<int> adj[]
etc.
🧩 Matrix: int dp[100][200], vector<vector<bool>> vis(100, vector<bool> (200, 0))
etc.
🕗 Arrays that have been decayed or declared at runtime like int arr[n]
.
📝 Rvalue Literals like "Hello", false, 'z', isSafe(i, j), dfs(u)
.
🧱 User defined structs / classes like Point
, Node
.
🤯 Even nested datatypes like map<string, vector<pair<char, unordered_set<long long>>>> WHATTT;
.
Note: For latest updates and a colored stderr version of this template, visit my Github.
Colored Template PreviewLight
Dark
How to use it?
Let's say you have different datatypes such as:
Examplechar Char = 'A';
int arr[] = {1, 2, 3, 4};
bitset<8> Bitset(100);
map<string, int> map_String_Int = {{"apple", 5}, {"banana", 3}, {"orange", 7}};
You can debug them like this debug(var1, var2, var3, var4, ...);
Exampledebug(Char, arr, Bitset, map_String_Int);
// Output
21: [Char = 'A' || arr = {1,2,3,4} || Bitset = 01100100 || map_String_Int = {("apple",5),("banana",3),("orange",7)}]
If you have user defined structs / classes, you just need to make a print()
function, and use debug(...)
like you do :)
User-Defined struct/class printing.struct Point
{
int x{};
int y{};
};
void print(Point ob)
{
cerr << "(" << ob.x << "," << ob.y << ")";
}
In instances where array have decayed into pointer, or you declared array at runtime, use debugArr(arr, n);
What is Array Decay?When an array is passed to a function, it is automatically converted to a pointer to the first element of the array. This means that the function cannot access the size of the array, and it can only access the elements of the array through the pointer.
Note:
- You don't need to remove
debug(...)
statements in your code when submitting it.
- On platforms like Codeforces, there's a macro called
ONLINE_JUDGE
that's defined, automatically disregarding all your debug statements. This ensures your solution will be accepted unless there's a logical error.
How to Setup?
- Copy this template into your own templates. The output will be directed to the stderr stream.
- Alternatively you can make a separate header file and include this into your template
#ifndef ONLINE_JUDGE
#include "template.cpp"
#else
#define debug(...)
#define debugArr(...)
#endif
- When using it for LeetCode uncomment
#define cerr cout
and before submitting change #ifndef
to #ifdef
to ignore debug(...);
. For convenience, after changing it, copy it, and keep it pinned in your clipboard for repetitive use.
For Complete Beginners who need step by step tutorial (for VS Code), follow these steps:
Steps - Open VS Code and my Github
- In your workspace, create a file template.cpp
- Copy content of my template_cpp11_std.cpp into your template.cpp
- Press Ctrl + Shift + P to open Command Pallete
- Search Configure User Snippet and click on cpp.json
- Now copy the content of my cpp.json into your cpp.json file
- Now you have configured your user snippets. Create a main.cpp file and type wow and press TAB!!! Magic!!!
Additionally, you can install Competitive Programming Helper
extension from VS Code to make your journey easy.
Now for LeetCode
- Uncomment
#define cerr cout
and copy this template - Keep it pinned in your clipboard. If you are using windows, you can press Win + V to open clipboard.
- When solving DSA problems in LeetCode, paste this above
class Solution
and use debug normally. - Before submitting, change
#ifndef
to #ifdef
to ignore debug(...);
.
If you liked this blog, please upvote it, I'd really be grateful :)
Edit: Looking for something unique and fun? Check out my other blog on How doing CP and GYM are Alike