Please visit the source code repository on GitHub.
Download: prettyprint.hpp (C++11), prettyprint98.hpp (C++98/03), or the zip ball or tar.gz ball.
Aug. 2014: Some refactoring of the C++11 code. Tuples and pairs are now containers, and the special logic has been moved into a dedicated template used for printing the container body. This removes several dodgy overloads from the namespace std. Some old code and comments have also been removed, and more demo cases added.
Nov. 2011: There is now a new wrapper bucket_print
, which iterates
only over one bucket of containers based on hash tables (such as the unordered_*
containers in the standard library). See below for details.
We are thrilled to announce that the indomitable Stephan T Lavavej has been inspired by this library to make an episode of Advanced STL about container pretty printing — thank you very much!
We will try to incorporate some of STL’s excellent ideas into this library, stay tuned. In the meantime, check out his own pretty printer code!
Updates: Following STL’s ideas, the library has now been improved to support static arrays directly without the need for a wrapper. Also, the library should now be usable in MS Visual Studio 2010.
Furthermore, there is now a version that works
in C++98/03 compliant compilers. It uses TR1 tuples by default, but all dependence on TR1
libraries can be removed by defining NO_TR1
.
Download prettyprint.hpp
and place it in your source directory. Add #include "prettyprint.hpp"
to your source file. You are ready!
Note: This library relies on C++11 features. With gcc, pass the option -std=c++11
.
cxx-prettyprint is a header-only library for C++ which provides printing via the <<-operator for any container class. Before we go into the details, let us quickly think about what we need to do:
[]
.[3]
.[3, -11, 137]
;
note that there are n − 1 delimiters.The cxx-prettyprint library provides precisely this functionality. We are using the following default settings for the delimiters (but see below for how to customize):
,
” (comma, space).(1, foo)
.{1, 5, 11}
.[1.4, -1.2, Inf, 88.6]
.These lexical conventions attempt to mimic popular mathematical notation for tuples, sets and vectors, respectively.
Suppose we map integers to sets of strings.
The output would look like so:
Raw C arrays are handled the same way as “proper” containers:
However, if the array size is not known at compile time, a wrapper may be invoked via pretty_print_array(arr, size)
.
Certain containers based on hash tables offer an additional interface to the internal buckets of the hash
table. This interface comes in the form of local iterators, accessed via begin(n)
and end(n)
,
where n
indicates the bucket number. Examples of such containers are the unordered_*
containers
from the standard libray.
Individual buckets may be printed with the wrapper bucket_print
, used as follows:
The delimiters that are used by the output operation are deduced from compile-time static class constants.
In particular, if T
denotes any container type, then the appropriate delimiters are defined
by the following templated structure:
The templates are parametrized on TChar
, the type of the character,
which is char
for std::cout
and wchar_t
for
std::wcout
. You must define delimiters<T, TChar>::values
for your container type T
. For example, the default delimiters for
TChar = char
are declared as follows:
The most straight-forward way to override delimiters for a particular container is to specialize the delimiters
struct
accordingly. For example, if we want special delimiters for a vector of doubles, we specialize as follows:
An alternative solution is to provide your own delimiters class. That is a class with a public, static constant named values
and of type pretty_print::delimiters_values<TChar>
, where you must provide a concrete instance of TChar
suitable
for your output operation (usually char
). With such a class, say MyDelims
, you can invoke a wrapper class for any
container, say v
:
(The wrapper class custom_delims
uses type erasure to call the relevant internal helper instance
of the type of v
.) Your delimiter class could for example be declared as follows:
As a rule of thumb: Specialize pretty_print::delimiters
if you want uniform delimiters for
a particular container type, and use the pretty_print::custom_delims
wrapper with your own
delimiter class if you want to use a fixed set of delimiters for a variety of containers on a one-off basis.
The key component of the library is a combination of std::enable_if
together with
a typetrait is_container<T>
. This type trait uses the SFINAE (substitution failure
is not an error) model to determine whether a type T::const_iterator
exists. If yes,
operator<<()
is overloaded for type T
, and a loop from begin()
to end()
is performed, inserting the appropriate delimiters.
The custom_delims
helper class uses type-erasure to take an arbitrary container object
and instantiate the correct template of the internal helper class with the user-provided delimiter class.
NO_TR1
.
This library is the product of many great contributions to my questions on StackOverflow and on Channel 9. Here is the original StackOverflow working topic, here is the follow-up on printing tuples, and finally the Channel 9 thread where it all came together. Credits go to Marcelo Cantos for the initial approach, to Sven Groot for an improved, self-contained solution which became the foundation for my code, and to Xeo for the tuple-printing code.
Possible avenues for future improvements:
is_container
typetrait is too aggressive more carefully. Examples where this library breaks existing code are most appreciated!If you like to help out, just send me a message on GitHub, email me patches or suggestions, or send pull requests.
louisdx