perr
- or pretty error - a possibly convenient (if a bit slow) replacement for std::cerr
.
Decorates output with source points and handles STL containers out of the box.
Excellent for toy projects and debugging homework :-)
Messages printed to the standard error are prefixed with the file name and the line number, for example:
#include "perr.h"
int main() {
perr << "Hello world!";
};
This prints the hello-world message prefixed with the source location:
hello-world.cpp : 4 Hello world!
The new line at the end is inserted automatically.
Tweak the message prefix to your liking inside the stream
method.
You can change colors, add timestamps or the function name.
To disable colors, compile with -DNOCOLOR
.
The header contains overloads for convenient printing of STL containers, such as a vector, a map, or a set.
The listing shows how to print a vector of integers.
#include <vector>
#include "perr.h"
int main() {
std::vector< int > v = { 1, 2, 3 };
perr << v;
v.push_back(44);
perr << v;
v.clear();
perr << v;
};
This produces:
vector-int.cpp : 6 V[1, 2, 3]
vector-int.cpp : 9 V[1, 2, 3, 44]
vector-int.cpp : 12 V[]
Other containers are shown below.
The multi versions of maps and sets are marked with small letters (m
vs M
and s
vs S
).
Unordered maps and sets use curly braces {}
as opposed to angled brackets <>
.
(Mnemonic: <
is used for comparison, hence ordered containers.)
Array ┇ A[1, 2, 3, 4]
Vector ┇ V[1, 2, 3, 4]
List ┇ L(1 <-> 2 <-> 3 <-> 4)
Set ┇ S<1, 2, 3, 4>
Multiset ┇ s<1, 1, 2, 2>
Map ┇ M<'a' : 1, 'b' : 2, 'c' : 3>
Multimap ┇ m<'a' : 1, 'a' : 2, 'b' : 3>
Unordered Set ┇ S{1, 2, 3, 4}
Unordered Multiset ┇ s{1, 2, 2, 2}
Unordered Map ┇ M{'a' : 1, 'c' : 2}
Unordered Multimap ┇ m{'a' : 1, 'a' : 2}
Deque ┇ D[1, 2, 3]
To print a container of structs, define operator<<
only for the struct,
like so:
#include <vector>
#include "perr.h"
struct Rectangle {
int height;
int width;
};
std::ostream& operator<< (std::ostream& os, Rectangle const& r) {
os << "{" << r.height << "x" << r.width << "}";
return os;
};
int main() {
std::vector< Rectangle > vr = { {2, 3}, {4, 5} };
perr << vr;
}
This will output:
vector-struct.cpp : 16 V[{2x3}, {4x5}]
You do not have to manually remove calls to perr <<
before submitting code
to an online checking system (that does not have the perr.h
header).
Instead, hide the #include
behind an #ifdef
and let the compiler nuke calls to perr <<
.
#ifdef PERR
#include "perr.h"
#else
static struct Perr {template <typename T> constexpr Perr& operator<<(T const &any) {return *this;}} perr;
#endif
perr
is a macro that creates a temporary PrettyStream
object and
calls the .stream()
method immediately after.
A call to the stream()
method returns std::cerr
.
#define perr prettystreams::PrettyStream(std::cerr, __PRETTY_FUNCTION__, __FILE__, __LINE__).stream()
The constructor captures the name of the function and the file and the line number.
The .stream()
method pretty-prints this information to the underlying std::cerr
stream before returning it.
The caller gets std::cerr
but with a nice line prefix.
When the PrettyStream
object is destroyed, the destructor prints std::endl
to the stream.
This is neat and simple (and predates std::basic_stacktrace
by a few years).
The implementation is enclosed in the prettystreams
namespace.
Output operators for std
containers extend the std
namespace.
I have been using perr.h
for debugging toy projects and competitive coding tasks.
The current version is sprinkled with new language features (parameter packs, requires
clauses, etc).
Compile with -std=c++20
(gcc/clang).
Some functionality - such as printing out heaps as ASCII art - has been removed. I may restore it in the future.