Традиционный дебаг
Наверное, каждый спортивный программист хотя бы раз выводил содержимое контейнера, массива или просто значение переменной во время дебага. В этот момент появляются такие вот уродливые конструкции(взято с потолка):
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, какая разница, если это нелья записать кратко?!
Дебаг с f_dbg()
Мне надоело бесконечно писать эти циклы, поэтому я сделал четырехстрочник, который может вывести значения практически чего угодно, хранящего встроенные типы. Вывод сделан в стиле питона. Конечно, у него есть некоторые ограничения, но в целом он мне нравится.
Вы можете найти его здесь. Он использует некоторые фичи c++17, поэтому выберите правильный компилятор. 4-строчная версия сгенерирована из полной на сайте http://removelinebreaks.net/
Как работает форматированный вывод
Назовем массивом c-массив, вектор, дек, array. Тогда f_dbg()
может вывести подмассив. Чтобы она сделала это, вы передаете название массива и координаты крайних ячеек подмассива — ячейки с наименьшими координатами и ячейки с наибольшими координатами в подмассиве. Если они слишком большие, f_dbg()
уменьшает их, чтобы они были внутри подмассива. По умолчанию начальная ячейка — первая ячейка массива, конечная — последняя ячейка массива.
Если тип элементов в массиве тоже какой-то массив, f_dbg()
вызывается рекурсивно от этого элемента, пока не достигнет элементарного типа — int, char, double и т.д. Это значение выводится, и все, собственно.
Другие структуры данных вроде map, set не имеют индексов, и поэтому выводятся полностью — от начала до конца. В map f_dbg()
вызывается и от ключа, и от значения.
Пары выводятся так же: рекурсивно вызывается f_dbg()
от первого элемента, потом от второго.
Например:
vector<vector<string>> d = {{"fjs", "sdf"}, {"sas"}};
f_dbg(d);
вывод: [[fjs,sdf],[sas]]
/*-----------------------------------------------*/
Основные типы можно выводить, используя dbg()
и макрофункцию _()
. Она использует синтаксис dbg()
, чтобы вывести имя переменной, двоеточие, значение, запятую. Получится так:
string s = "Hello, world!";
dbg(_(s));
вывод: s: Hello world,
/*-----------------------------------------------*/
Надеюсь, эти 4 строчки сохранят немного вашего бесценного времени во время контеста.
P.P.S. Если вы захотите адаптировать код к c++11/14, я не возражаю, если вы склонируете этот блог для (c++11/14 эдишн). Или вы можете предложить ваш код, и я добавлю его сюда, чтобы все версии были вместе.
UPD1: добавлен вывод unsigned int, long long, unsigned long long, long double, double UPD2: добавлен вывод bitset