Listing D
<code>
Listing B
 
#include <iostream>
#include <string>
#include <list>
#include <vector>
 
 
template< class Function>
  class basic_range_writer
{
public:
  basic_range_writer( Function f)
    : m_f( f)
  {}
 
  template< class CharType, class CharTraits>
    void write_prefix( std::basic_ostream< CharType, CharTraits> & streamOut)
  {
    // default - don't write any prefix
  }
  template< class CharType, class CharTraits>
    void write_after_element( std::basic_ostream< CharType, CharTraits> & streamOut)
  {
    // default - write ", "
    static std::basic_string< CharType> strDefault =
      std::basic_string< CharType>() + ( CharType)',' + ( CharType)' ';
    streamOut << strDefault;
  }
  template< class CharType, class CharTraits>
    void write_suffix( std::basic_ostream< CharType, CharTraits> & streamOut)
  {
    // default - write " "
    static std::basic_string< CharType> strDefault =
      std::basic_string< CharType>() + ( CharType)' ';
    streamOut << strDefault;
  }
 
  Function m_f;
};
 
template< class Function, class CharType>
  class range_writer
{
public:
  range_writer(
      Function f,
      const CharType * strPrefix,
      const CharType * strAfterElement,
      const CharType * strSuffix)
    : m_f( f),
      m_strPrefix( strPrefix),
      m_strAfterElement( strAfterElement),
      m_strSuffix( strSuffix)
  {}
 
  // ... no suffix, no prefix
  range_writer(
      Function f,
      const CharType * strAfterElement)
    : m_f( f),
      m_strAfterElement( strAfterElement)
  {}
 
  template< class CharTraits>
    void write_prefix( std::basic_ostream< CharType, CharTraits> & streamOut)
  {
    streamOut << m_strPrefix;
  }
  template< class CharTraits>
    void write_after_element( std::basic_ostream< CharType, CharTraits> & streamOut)
  {
    streamOut << m_strAfterElement;
  }
  template< class CharTraits>
    void write_suffix( std::basic_ostream< CharType, CharTraits> & streamOut)
  {
    streamOut << m_strSuffix;
  }
 
  Function m_f;
  std::basic_string< CharType> m_strPrefix, m_strAfterElement, m_strSuffix;
};
 
 
template< class Iterator, class FormatterClass>
  class range_with_formatter
{
public:
  range_with_formatter( Iterator itFirst, Iterator itLast, FormatterClass formatter)
    : m_itFirst( itFirst),
      m_itLast( itLast),
      m_formatter( formatter)
  {}
  template< class Container>
    range_with_formatter( Container & cont, FormatterClass formatter)
    : m_itFirst( cont.begin()),
      m_itLast( cont.end()),
    m_formatter( formatter)
  {}
 
  Iterator m_itFirst, m_itLast;
  FormatterClass m_formatter;
};
 
// allow writing range_with_formatter to streams
template< class CharType, class CharTraits, class Iterator, class FormatterClass>
  std::basic_ostream< CharType, CharTraits> & operator<< (
    std::basic_ostream< CharType, CharTraits> & streamOut,
    range_with_formatter< Iterator, FormatterClass> & range)
{
  Iterator itFirst = range.m_itFirst, itLast = range.m_itLast;
  range.m_formatter.write_prefix( streamOut);
  while ( itFirst != itLast)
  {
    // write the element, formatted!!!
    range.m_formatter.m_f( streamOut, *itFirst);
    ++itFirst;
    if ( itFirst != itLast)
    {
      range.m_formatter.write_after_element( streamOut);
    }
    else
    {
      // last element
    }
  }
  range.m_formatter.write_suffix( streamOut);
  return streamOut;
}
 
 
// (Helper - used below, for range( Iterator, Iterator) function)
// default formatter for elements - just writes them to the stream
class default_transformation
{
public:
  template< class StreamType, class Type>
  void operator() ( StreamType & streamOut, const Type & value)
  {
    streamOut << value;
  }
};
 
//
// allow returning formatters
//
// ... provide only the transformer function - for each element
//     (default prefix, after element, suffix)
template< class Function>
  basic_range_writer< Function> formatter( Function f)
{
  return basic_range_writer< Function>( f);
}
// ... provide the transformer function - for each element
//     AND prefix, after element, suffix
template< class Function, class CharType>
  range_writer< Function, CharType> formatter(
    Function f,
    const CharType * strPrefix,
    const CharType * strAfterElement,
    const CharType * strSuffix)
{
  return range_writer< Function, CharType>( f, strPrefix, strAfterElement, strSuffix);
}
// ... provide the transformer function - for each element
//     AND the after element (no suffix, no prefix - they are empty)
template< class Function, class CharType>
  range_writer< Function, CharType> formatter(
    Function f,
    const CharType * strAfterElement)
{
  return range_writer< Function, CharType>( f, strAfterElement);
}
// ... provide the prefix, after element, suffix
//     (default transformer)
template< class CharType>
  range_writer< default_transformation, CharType> formatter(
    const CharType * strPrefix,
    const CharType * strAfterElement,
    const CharType * strSuffix)
{
  return range_writer< default_transformation, CharType>(
    default_transformation(), strPrefix, strAfterElement, strSuffix);
}
 
//
// allow printing ranges
//
// Range with formatter
// (you provide the beginning & end of the range AND the formatter)
template< class Iterator, class FormatterClass >
  range_with_formatter< Iterator, FormatterClass>
    range( Iterator itFirst, Iterator itLast, FormatterClass formatter)
{
  return range_with_formatter< Iterator, FormatterClass>( itFirst, itLast, formatter);
}
 
// Range with default formatter
// (you provide the beginning & end of the range; you're provided a default formatter,
// which just writes the elements)
template< class Iterator>
  range_with_formatter< Iterator, basic_range_writer< default_transformation> >
    range( Iterator itFirst, Iterator itLast)
{
  default_transformation default_format;
  basic_range_writer< default_transformation> formatter( default_format);
  return range_with_formatter<
    Iterator,
    basic_range_writer< default_transformation> >( itFirst, itLast, formatter);
}
 
//
// allow printing containers
//
// Continer with formatter
// (you provide the Container AND the formatter)
template< class Container, class FormatterClass >
  range_with_formatter< typename Container::const_iterator, FormatterClass>
    container( const Container & cont, FormatterClass formatter)
{
  return range_with_formatter< typename Container::const_iterator, FormatterClass>(
    cont.begin(), cont.end(), formatter);
}
// Container with default formatter
// (you provide the container; you're provided a default formatter,
// which just writes the elements)
template< class Container>
  range_with_formatter< typename Container::const_iterator, basic_range_writer< default_transformation> >
    container( const Container & cont)
{
  default_transformation default_format;
  basic_range_writer< default_transformation> formatter( default_format);
  return range_with_formatter<
    typename Container::const_iterator,
    basic_range_writer< default_transformation> >( cont.begin(), cont.end(), formatter);
}
 
 
 
 
 
//////////////////////////////////////////////
// EXAMPLES
 
// prefix each element by its index
class PrefixByIndex
{
public:
  PrefixByIndex()
    : m_idxCurrent( 0)
  {}
 
  template< class StreamType, class Type>
  void operator()( StreamType & streamOut, const Type & value)
  {
    streamOut << "[" << m_idxCurrent << "] " << value;
    ++ m_idxCurrent;
  }
private:
  int m_idxCurrent;
};
 
 
int _tmain(int argc, _TCHAR* argv[])
{
 
  ///////////////////////////////////////////////////////////
  // printing ranges
 
  // printing C-like array of numbers
  int aMonths [] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
  int nMonthsCount = ( sizeof( aMonths) / sizeof( aMonths[ 0]));
  std::cout << range( aMonths, aMonths + nMonthsCount ) << std::endl ;
 
  typedef std::list< std::string> StringsArray;
  StringsArray aNames;
  aNames.push_back( "John");
  aNames.push_back( "James");
  aNames.push_back( "Corina");
  // printing as range
  std::cout
    << range( aNames.begin(), aNames.end() ) << std::endl ;
 
  ///////////////////////////////////////////////////////////
  // printing containers
 
  std::cout
    << container( aNames) << std::endl ;
 
  std::cout
    << container( aNames, formatter( "{", "}, {", "}")  ) << std::endl ;
  std::cout
    << container( aNames, formatter( PrefixByIndex(), "{", "}, {","}") )
    << std::endl ;
  std::cout
    << container( aNames, formatter( PrefixByIndex(), ", ") )
    << std::endl ;
  std::cout
    << container( aNames, formatter( "[", "]\n[", "]") )
    << std::endl ;
  std::cout
    << container( aNames, formatter( PrefixByIndex(), "'", "'\n'", "'") )
    << std::endl ;
  std::cout
    << container( aNames, formatter( PrefixByIndex(), "\n") )
    << std::endl ;
 
  return 0;
}
</code>