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>