Традиционный дебаг
Наверное, каждый спортивный программист хотя бы раз выводил содержимое контейнера, массива или просто значение переменной во время дебага. В этот момент появляются такие вот уродливые конструкции:
vector<int> a[4][6] = {{{2,3}, {4}}, {{6,2}, {4,5}}};
for(int i = 0; i < size(a); ++i, cout << endl){
for(int j = 0; j < size(a[i]); ++j, cout << endl){
for(int k : a[i][j]){
cout << k << ' ';
}
}
}
О, господи, да еще и гарантированная проверка, что счетчик не выходит за пределы массива! 2D, 3D, какая разница, если это нелья записать кратко?! Да еще эти endlы вместо пустых ячеек...
Дебаг с dbg()
Мне надоело бесконечно набивать эти циклы, поэтому я написал несколько строчек, которые могут напечатать значения практически чего угодно, хранящего встроенные типы. Вывод сделан в стиле питона. Конечно, у этого кода есть некоторые ограничения, но в целом он мне нравится. В большой степени основан на этой посылке tourist
Вы можете найти мой код здесь.
Компактная версия сгенерирована из полной на сайте http://removelinebreaks.net/
Как работает dbg()
Допустим, у нас есть вложенные друг в друга контейнеры, которые мы можем для простоты рассматривать как просто многомерный массив со специфическими измерениями. dbg()
может вывести название и границы подмассива такого массива, а потом и сам подмассив.
Например:
string g[2][2] = {{"ghdgh", "5445w"}, {"fghd", "sd3535f"}};
dbg(g,0,1,0,1,0,1);
// вывод:
[g,0,1,0,1,0,1]:
[["gh","54"],
["fg","sd"]]
Чтобы она сделала это, вы передаете ей по [две закрытые границы] для каждого измерения, причем можно опустить несколько последних границ. Если они слишком большие, dbg()
уменьшает их, чтобы они были внутри массива. По умолчанию начальная и конечная граница для каждого измерения устанавливаются на начало и конец каждого измерения.
ВНИМАНИЕ! Если вы передаете границы [l, r]
в измерение, которое map
или set
, вывод начинается с l-ного элемента и заканчивается r-ным или последним элементом контейнера.
Если тип элемента в данном измерении не какая-нибудь просто pair<int, int> или string, вывод запускается от этого элемента, пока он не достигнет элементарного типа.
/*-----------------------------------------------*/
Допустим, нужно посмотреть элементы в контейнере с 1го по 3ий.
Сравните:
map<vector<int>, vector<string>> a = {{{5,4},{"sert","gsdfs"}}, {{2,6},{"getr"}}, {{6},{"agert","ertj"}}};
// традиционная версия
auto l = begin(a), r = begin(a);
advance(l,1), advance(r, min(int(SIZE(a)), 4));
for(; l != r; ++l){
cout << "{"; for(auto &ff : (*l).first) cout << ff << ","; cout << "}";
cout << "{"; for(auto &ff : (*l).second) cout << ff << ","; cout << "}\n\n";
} cout << "\n";
// dbg
dbg(a,1,3);
традиционная версия выводит:
{5,4,}{sert,gsdfs,}
{6,}{agert,ertj,}
// `dbg()` выводит:
[a,1,2]:
[([5,4],["sert","gsdfs"]),
([6],["agert","ertj"])]
Допустим, нужно вывести несколько переменных
int t = 5; char u = 'R';
pair<pair<double, unsigned int>, pair<int, string>> v = {{234.34534, 42}, {133, "IOI"}};
// традиционная версия:
#define fi first
#define se second
cout << t << " | " << u << " | " << "{ { " << v.fi.fi << "," << v.fi.se << " }{ " << v.se.fi << "," << v.se.se << " }\n";
// вывод:
cout << t << " | " << u << " | " << "{ { " << v.fi.fi << "," << v.fi.se << " }{ " << v.se.fi << "," << v.se.se << " }\n";
// dbg
dbg(t), dbg(u), dbg(v);
// вывод
[t]: 5
[u]: R
[v]: ((234.345340,42),(133,"IOI"))
/*-----------------------------------------------*/
Надеюсь, этот код сохранит немного вашего бесценного времени на контестах.
UPD: полностью переписан код