FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
TABLE OF CONTENTS
July 20, 2007
An Enhanced ostream_iterator

Getting what you want from std::ostream_iterator.

(Page 1 of 3)
Matthew Wilson
Have you ever wanted a smarter std::ostream_iterator? Matthew Wilson shows you how.

Matthew Wilson is a software development consultant for Synesis Software, and creator of the STLSoft libraries. Matthew can be contacted via http://www.synesis.com.au/. This article was excerpted from his book Extended STL, Volume 1 (ISBN 0321305507). Copyright (c) 2007 Addison Wesley Professional. All rights reserved.

I have benefited greatly from criticism, and at no time have I suffered a lack thereof.
—Winston Churchill

I'm so gorgeous, there's a six-month waiting list for birds to suddenly appear, every time I am near!
—Cat, Red Dwarf

Introduction

Do you ever find yourself wanting to output the contents of a sequence where the elements are to be indented, perhaps by a tab space ('\ t'), as in the following example?

Header Files:
  H:\ freelibs\ b64\ current\ include\ b64\ b64.h
  H:\ freelibs\ b64\ current\ include\ b64\ cpp\ b64.hpp
Implementation Files:
  H:\ freelibs\ b64\ current\ src\ b64.c
  H:\ freelibs\ b64\ current\ test\ C\ C.c
  H:\ freelibs\ b64\ current\ test\ Cpp\ Cpp.cpp

Using std::ostream_iterator, this is disproportionately difficult and inelegant to achieve. Consider that we're searching for source files under the current directory, using the recls/STL library (itself an adaptation of a collection in what should now be, after reading Part II, characteristic STL extension style). recls/STL provides the recls::stl::search_sequence collection (a typedef of recls::stl::basic_search_sequence<char>), to which we pass the search directory, pattern, and flags. We can use this in combination with std::copy() and std::ostream_iterator, as shown in Listing 1, to achieve the desired output.

Listing 1: Formatting Output Using std::ostream_iterator

1 typedef recls::stl::search_sequence srchseq_t;
2 using recls::RECLS_F_RECURSIVE;
3 
4 srchseq_t headers(".", "*.h|*.hpp", RECLS_F_RECURSIVE);
5 srchseq_t impls(".", "*.c|*.cpp", RECLS_F_RECURSIVE);
6 
7 std::cout << "Header Files:" << std::endl << "\ t";
8 std::copy(headers.begin(), headers.end()
9  , std::ostream_iterator<srchseq_t::value_type>(std::cout, "\ n\ t"));
10 std::cout << "\ r";
11 
12 std::cout << "Implementation Files:" << std::endl << "\ t";
13 std::copy(impls.begin(), impls.end()
14 , std::ostream_iterator<srchseq_t::value_type>(std::cout, "\ n\ t"));
15 std::cout << "\ r";

Obviously, there's a degree of mess here in that the formatting we seek to apply on lines 8–9 and 13–14 leaks out into lines 7, 10, 12. and 15. I'm certain you can imagine how, in more complex cases, this can lead to convoluted and fragile code, something that would just not happen were std::ostream_iterator a tiny bit smarter. This chapter describes how std::ostream_iterator can be enhanced in a simple but crucial way, in the form of stlsoft::ostream_ iterator.

Before we look in depth at the problem and the simple solution, let's see that solution in action (Listing 2).

Listing 2: Formatting Output Using stlsoft::ostream_iterator

1 typedef recls::stl::search_sequence srchseq_t;
2 using recls::RECLS_F_RECURSIVE;
3 
4 srchseq_t headers(".", "*.h|*.hpp", RECLS_F_RECURSIVE);
5 srchseq_t impls(".", "*.c|*.cpp", RECLS_F_RECURSIVE);
6 
7 std::cout << "Header Files:" << std::endl;
8 std::copy(headers.begin(), headers.end()
9     , stlsoft::ostream_iterator<srchseq_t::value_type>(std::cout
10                           , "\ t", "\ n"));
11 
12 std::cout << "Implementation Files:" << std::endl;
13 std::copy(impls.begin(), impls.end()
14     , stlsoft::ostream_iterator<srchseq_t::value_type>(std::cout
15                           , "\ t", "\ n"));

Now the formatting is entirely located where it should be, in the invocation of the iterator's constructor. Naturally, this component can be used easily in formatted output that employs different levels of indentation.

(If we wanted to be especially pious with regards to DRY SPOT, we might declare a single instance of stlsoft::ostream_iterator with the required prefix and suffix and pass it to the two invocations of std::copy(). But that's not as clear-cut as you might think, as we'll shortly see.)

1 An Enhanced ostream_iterator | 2 std::ostream_iterator | 3 A Clash of Design Principles? Next Page
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK