Традиционный дебаг
Наверное, каждый спортивный программист хотя бы раз выводил содержимое контейнера, массива или просто значение переменной во время дебага. В этот момент появляются такие вот уродливые конструкции(взято с потолка):
vector<int> a[2][2] = {{{2,3}, {4}}, {{6,2}, {4,5}}};
for(int i = 0; i < size(a); ++i, cout << endl){
for(int j = 0; j < min(4, int(size(a[i]))); ++j, cout << endl){
for(int k = 0; k < min(3, int(size(a[i][j]))); ++k){
cout << a[i][j][k] << ' ';
}
}
}
О, господи, да еще и гарантированная проверка, что счетчик не выходит за пределы массива! 2D, 3D, какая разница, если это нелья записать кратко?! Да еще эти endlы вместо пустых ячеек.
Дебаг с f_dbg()
Мне надоело бесконечно писать эти циклы, поэтому я сделал трехстрочник, который может вывести значения практически чего угодно, хранящего встроенные типы. Вывод сделан в стиле питона. Конечно, у него есть некоторые ограничения, но в целом он мне нравится.
Вы можете найти его здесь. Он использует некоторые фичи c++17, поэтому выберите правильный компилятор.
3-строчная версия сгенерирована из полной на сайте http://removelinebreaks.net/
Как работает форматированный вывод
Назовем массивом c-массив, вектор, дек, array. Тогда f_dbg()
может вывести подмассив. Чтобы она сделала это, вы передаете ей по две границы для каждого измерения, причем можно опустить несколько последних границ. Если они слишком большие, f_dbg()
уменьшает их, чтобы они были внутри подмассива. По умолчанию начальная и конечная граница для каждого измерения устанавливаются на начало и конец каждого измерения.
Если тип элементов в массиве тоже какой-то массив, f_dbg()
вызывается рекурсивно от этого элемента, пока не достигнет элементарного типа — int, char, double и т.д. Это значение выводится, и все, собственно.
Другие структуры данных вроде map, set не имеют индексов, и поэтому выводятся полностью: от начала до конца. В map f_dbg()
вызывается и от ключа, и от значения.
Пары выводятся так же: рекурсивно вызывается f_dbg()
от первого элемента, потом от второго.
/*-----------------------------------------------*/
Сравните:
// traditional way(modified for uderstandability)
int x1 = 1;
int x2 = size(a)-1;
for(int i = x1; i <= x2; ++i, cout << endl){
int y1 = 0;
int y2 = min(3, int(size(a[i]))-1);
for(int j = y1; j <= y2; ++j, cout << endl){
for(int k : a[i][j]){
cout << k << ' ';
}
}
}
// f_dbg()
f_dbg(a,1,1e9,0,3);
вывод традиционной версии:
6 2
4 5
/*...endls...*/
Вывод f_dbg()
[[[6,2],[4,5],[],[]]
[[],[],[],[]]
[[],[],[],[]]]
/*-----------------------------------------------*/
Основные типы можно выводить, используя dbg()
и макрофункцию _()
. Она использует синтаксис dbg()
, чтобы вывести имя переменной, двоеточие, значение, запятую. Получится так:
string s = "Hello, world!";
dbg(_(s));
вывод: s: Hello world,
/*-----------------------------------------------*/
Надеюсь, этот код сохранит немного вашего бесценного времени во время контеста.
P.S. Если вы захотите адаптировать код к c++11/14, я не возражаю, если вы склонируете этот блог для (c++11/14 эдишн). Или вы можете предложить ваш код, и я добавлю его сюда, чтобы все версии были вместе.
UPD1: добавлен вывод unsigned int, long long, unsigned long long, long double, double
UPD2: добавлен вывод bitset
UPD3: Немного изменен интерфейс и описание интерфейса функций