FastFormat's format_iterator in Dr. Dobb's
format_iterator() component features in my recent article published in Dr. Dobb's. In this post, I'll provide tutorial information and links to additional resources for any interested readers.
The design and implementation of the FastFormat library's format_iterator() component features in my recent article published in Dr. Dobb's. In this post, I'll provide tutorial information and links to additional resources for any interested readers.
The new article, "C++ and format_iterator", describes how FastFormat's flexiblity, expressiveness and 100% type-safety has been combined with the output iterator concept to produce the fastformat::format_iterator component.
Applying STL-extension techniques described in Extended STL, volume 1, the format_iterator() component is able to create an output iterator that can receive arbitrate types, apply a format string or arbitrary complexity, and write to an arbitrary sink.
Let's consider a few examples. First, assume inclusion of the following set of FastFormat header files:
#include <fastformat/ff.hpp> #include <fastformat/iterators/format_iterator.hpp> #include <fastformat/sinks/ostream.hpp>
Now, let's imagine we have a sequence of strings. For simplicity, I'll just use an array of pointers to C-style strings:
char const* strings[] = { "abcde", "f", "ghi" };
If we want to write this sequence to std::cout, we can use std::ostream_iterator:
std::copy( strings, strings + 3 , std::output_iterator<char const*>(std::cout));
This will produce the output
abcdefghi
If we want to write each item to a separate line we can apply a suffix:
std::copy( strings, strings + 3 , std::output_iterator<char const*>(std::cout, "\n"));
This will produce the output
abcde f ghi
Unfortunately, that's where the flexibility of the standard component ends. As discussed in "C++ and format_iterator"'s prequel, "An Enhanced ostream_iterator" (itself an extracted chapter from Extended STL, volume 1), if you want to apply a prefix and a suffix - perhaps TAB and LF - you cannot reliably do so with std::ostream_iterator.
The next level of flexibility is to instead use STLSoft's stlsoft::ostream_iterator, which allows for both suffix and prefix (and is a syntactic-compatible replacement for std::ostream_iterator). Using it, we can provide the required tabbing:
std::copy( strings, strings + 3 , stlsoft::output_iterator<char const*>(std::cout, "\t", "\n"));
This will produce the output:
abcde
f
ghi
Although that's helpful in a lot of cases, it's still restrictive. Any more sophistication to the formatting and you're forced to explicitly iterate over the sequence. Furthermore, both of these still require that the type - char const* in this case - is specified to the creator function. That's just more eye-strain and unnecessary typing.
Using FastFormat's fastformat::format_iterator obviates both of these issues. First, it doesn't need to have the item type specified - any type that is understood by the FastFormat API can be processed:
std::copy(
strings, strings + 3
, <strong>ff::format_iterator</strong>(std::cout, "{0}"));
This will produce the output
abcdefghi
It can incorporate other literal components within the required format string:
std::copy(
strings, strings + 3
, <strong>ff::format_iterator</strong>(std::cout, "[{0}]"));
This will produce the output
[abcde][f][ghi]
It can incorporate special formatting instructions, such as making each field at least 3 and at most 4 characters wide, and left-aligned:
std::copy(
strings, strings + 3
, <strong>ff::format_iterator</strong>(std::cout, "[{0,3,4,<}]"));
This will produce the output
[abcd][f ][ghi]
And it can include additional arguments (again, of arbitrary type) from the local execution context:
std::string prefix = "\t";
char const* suffix = "\n";
std::copy(
strings, strings + 3
, <strong>ff::format_iterator</strong>(std::cout, "{1}{0}{2}", prefix, suffix));
This will produce the output
abcde
f
ghi
And putting it all together:
std::copy(
strings, strings + 3
, <strong>ff::format_iterator</strong>(std::cout, "{1}[{0,3,4,<}]{2}", prefix, suffix));
This will produce the output
[abcd]
[f ]
[ghi]
I hope that's helpful, and provides some of the Hows to go along with the Whys given in "the article". If you have any questions, requests, criticisms, please feel free to post on the FastFormat project Help Forum.

