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>