The Lazy Programmer

August 3, 2008

Formatting Output with Boost

Filed under: C#,Programming — ferruccio @ 9:20 pm
Tags: , ,

Sometimes a GUI is overkill for a project. You just need a simple tool to do some task. Perhaps it needs to be scripted. So you whip up a console mode program and you eventually have to output something. At this point, many developers will simply ignore the C++ iostreams library and reach for good old printf(). I can certainly understand why. The iostreams objects are easy enough to use for simple formatting tasks. However, when you need to do something more sophisticated, you will often find yourself digging through reference material, muttering "this should be easy…"

I’ve done C programming long enough so that I can usually whip up any format string off the top of my head. Need to print out a pointer value for debugging, that’s %08X. A left justified string padded out to 20 characters. No problem, it’s %-20s. I can’t say the same for C++. I know all the reasons for using iostreams: they’re type safe and extendable. If you create a new class, just define << and >> operators for that class and objects of that class can suddenly be read and written to files, strings and any other destination derived from ios_base.

A couple of years ago, I decided to make a conscious effort to use C++ idioms instead of C idioms in my code whenever possible. As part of that effort, I’ve managed to avoid #including any of the C headers most of the time. Preferring, instead, to hunt down and learn the equivalent C++ method of doing things. The effort has certainly paid off for me. My understanding of C++ has been enriched greatly. And I finally got past the hurdle of using templates as more than just a way of creating a containers of T. One of the last holdouts though, was formatted output. I would use iostreams as far as I could, but when things got complicated, I would just stick in a printf() and forget about it.

Finally, I ran across the Boost Format library and decided to try it for a small project. If you’re not familiar with the Boost libraries, you can check them out here.  The Format library allows you to mix printf() style formatting with iostreams. You get the type-safety and extendibility of  iostreams and the formatting strings we all know and love.

We’ll need some boilerplate code to get started:

#include <iostream>
#include <string>

#include "boost/format.hpp"

using namespace std;
using namespace boost;
Let’s do some simple formatting first.
int n = 5;
char *s = "hello!";
cout << format("n = %d, s = %s") % n % s << endl;

The format() creates a formatter which has an iostream compatible << operator. The % operator is used to pass parameters to the formatter. Note that the format string specifies an int (%d) and a string (%s) and we pass it those two values (n and s) via the % operator.

 
Now, what happens if we do this?
int n = 5;
int s = 10;
cout << format("n = %d, s = %s") % n % s << endl;

Note that for the second value to be output, we specified a string but gave it an int. Much to my surprise, when I ran this it printed out the value of the int (10). I was hoping it would throw an exception, but this is still better than crashing because it was expecting a char pointer.

Let’s try using an STL string and slightly more elaborate int formatting:

int n = 5;
string s = "hello, again!";
cout << format("n = %04X, s = %s") % n % s << endl;

This works as expected. We get the int formatted in hex and padded out to 4 places with leading zeroes.

There are some new formatting capabilities you wont find in printf: e.g.

cout << format("A%10T_B") << endl;

Will print the letter A, tab out to the 10th position (using _ as fill character) then print a B. This is very useful for printing tables of data.

You can print the arguments to format in any order by using positional notation:

int a = 10, b = 20, c = 30;
cout << format("%2% %3% %1%") % a % b % c << endl;

This will print "20 30 10".

I’ve barely scratched the surface of what you can do with the Boost Format library. You can get more detailed information at the Boost website.

Advertisements

2 Comments

  1. Good tip! I’ll use it next time, sure.

    Comment by Lazy Crazy Coder — August 5, 2008 @ 5:52 am

  2. Oh, I forget to say, that is much like pythons formatting. In python you can just write:

    “n = %d, s = %s” % (123, “Hello world”)

    I wonder if you can use boost::tuple with boost::format!

    Comment by Lazy Crazy Coder — August 5, 2008 @ 5:55 am


RSS feed for comments on this post.

Blog at WordPress.com.

%d bloggers like this: