////////////////////////////////////////////////////////////////////// // str_stream.h #ifndef STR_STREAM__H #define STR_STREAM__H #include <string> #include <sstream> #include <iostream> // forward declaration template< class char_type, class char_traits = std::char_traits< char_type> > class basic_str_stream; // ... helper - allow explicit conversion to string class as_string {}; template< class char_type, class char_traits> inline std::basic_ostream< char_type, char_traits> & operator<< ( std::basic_ostream< char_type, char_traits> & streamOut, const as_string &) { return streamOut; } #ifdef _MSC_VER #include "str_stream_vc_before.h" #endif // basic_str_stream - allow stream usage and then conversion to string template< class char_type, class char_traits> class basic_str_stream { typedef std::basic_stringstream< char_type, char_traits> stringstream_type; typedef std::basic_string< char_type, char_traits> string_type; public: // default construction basic_str_stream() {} // allow to_string like usage template< class type> basic_str_stream( const type & value) { *this << value; } stringstream_type & underlying_stream() const { return m_streamOut; } operator string_type() const { return m_streamOut.str(); } private: mutable stringstream_type m_streamOut; #ifndef NDEBUG public: void recalculate_string() const { m_string = m_streamOut.str(); } private: mutable string_type m_string; #endif }; // class basic_str_stream typedef basic_str_stream< char> str_stream; typedef basic_str_stream< wchar_t> wstr_stream; #ifndef _MSC_VER template< class char_type, class char_traits, class type> inline const basic_str_stream< char_type, char_traits> & operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, const type & value) { streamOut.underlying_stream() << value; #ifndef NDEBUG streamOut.recalculate_string(); #endif return streamOut; } // when as_string used, return the underlying string template< class char_type, class char_traits> inline const std::basic_string< char_type, char_traits> operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, const as_string & ) { // automatic conversion return streamOut; } // allow function IO manipulators template< class char_type, class char_traits> inline const basic_str_stream< char_type, char_traits> & operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, std::ios_base & (*func)( std::ios_base&) ) { func( streamOut.underlying_stream()); return streamOut; } template< class char_type, class char_traits> inline const basic_str_stream< char_type, char_traits> & operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, std::basic_ios< char_type, char_traits> & (*func)( std::basic_ios< char_type, char_traits> &) ) { func( streamOut.underlying_stream()); return streamOut; } template< class char_type, class char_traits> inline const basic_str_stream< char_type, char_traits> & operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, std::basic_ostream< char_type, char_traits> & (*func)( std::basic_ostream< char_type, char_traits> &) ) { func( streamOut.underlying_stream()); return streamOut; } // END OF - allow function IO manipulators #else #include "str_stream_vc_after.h" #endif #endif // End of file ////////////////////////////////////////////////////////////////////// // str_stream_vc_before.h /* IMPORTANT: this file contains only workarounds for VC DONOT include directly !!! */ #ifndef STR_STREAM_VC_BEFORE__H #define STR_STREAM_VC_BEFORE__H #ifndef STR_STREAM__H #error "DONOT include this file directly. #include 'str_stream.h' instead!" #endif #ifndef _MSC_VER #error "This file is intended only for Visual C" #endif namespace Private { // note: VC6 does not allow for partial specialization, // that's why I made this workaround template< class char_type, class char_traits> struct return_from_write_to_stream { template< class type> struct inner { typedef const basic_str_stream< char_type, char_traits> & return_type; }; template<> struct inner< as_string> { typedef std::basic_string< char_type, char_traits> return_type; }; }; // forward declaration template< class char_type, class char_traits, class type> inline typename return_from_write_to_stream< char_type, char_traits>::inner< type>::return_type write_to_stream ( const basic_str_stream< char_type, char_traits> & streamOut, const type & value); } // forward declaration template< class char_type, class char_traits, class type> inline typename Private::return_from_write_to_stream< char_type, char_traits>::inner< type>::return_type operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, const type & value); #endif // End of file ////////////////////////////////////////////////////////////////////// // str_stream_vc_after.h #ifndef STR_STREAM_VC_AFTER__H #define STR_STREAM_VC_AFTER__H #ifndef STR_STREAM__H #error "DONOT include this file directly. #include 'str_stream.h' instead!" #endif #ifndef _MSC_VER #error "This file is intended only for Visual C" #endif namespace Private { template< class char_type, class char_traits, class type> inline typename return_from_write_to_stream< char_type, char_traits>::inner< type>::return_type write_to_stream ( const basic_str_stream< char_type, char_traits> & streamOut, const type & value) { streamOut.underlying_stream() << value; #ifndef NDEBUG streamOut.recalculate_string(); #endif return streamOut; } } // namespace Private template< class char_type, class char_traits, class type> inline typename Private::return_from_write_to_stream< char_type, char_traits>::inner< type>::return_type operator<< ( const basic_str_stream< char_type, char_traits> & streamOut, const type & value) { return Private::write_to_stream( streamOut, value); } // allow function IO manipulators // again, VC does not handle templated functions, correctly; // therefore, we'll specialize for // basic_str_stream< char>, // basic_str_stream< unsigned char>, // basic_str_stream< signed char>, // basic_str_stream< wchar_t> // // if you need more, you can specialize it yourself, like shown below // ... basic_str_stream< char> inline const basic_str_stream< char> & operator<< ( const basic_str_stream< char> & streamOut, std::ios_base & (*func)( std::ios_base&) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< char> & operator<< ( const basic_str_stream< char> & streamOut, std::basic_ios< char> & (*func)( std::basic_ios< char> &) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< char> & operator<< ( const basic_str_stream< char> & streamOut, std::basic_ostream< char> & (*func)( std::basic_ostream< char> &) ) { func( streamOut.underlying_stream()); return streamOut; } // ... basic_str_stream< unsigned char> inline const basic_str_stream< unsigned char> & operator<< ( const basic_str_stream< unsigned char> & streamOut, std::ios_base & (*func)( std::ios_base&) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< unsigned char> & operator<< ( const basic_str_stream< unsigned char> & streamOut, std::basic_ios< unsigned char> & (*func)( std::basic_ios< unsigned char> &) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< unsigned char> & operator<< ( const basic_str_stream< unsigned char> & streamOut, std::basic_ostream< unsigned char> & (*func)( std::basic_ostream< unsigned char> &) ) { func( streamOut.underlying_stream()); return streamOut; } // ... basic_str_stream< signed char> inline const basic_str_stream< signed char> & operator<< ( const basic_str_stream< signed char> & streamOut, std::ios_base & (*func)( std::ios_base&) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< signed char> & operator<< ( const basic_str_stream< signed char> & streamOut, std::basic_ios< signed char> & (*func)( std::basic_ios< signed char> &) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< signed char> & operator<< ( const basic_str_stream< signed char> & streamOut, std::basic_ostream< signed char> & (*func)( std::basic_ostream< signed char> &) ) { func( streamOut.underlying_stream()); return streamOut; } // ... basic_str_stream< wchar_t> inline const basic_str_stream< wchar_t> & operator<< ( const basic_str_stream< wchar_t> & streamOut, std::ios_base & (*func)( std::ios_base&) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< wchar_t> & operator<< ( const basic_str_stream< wchar_t> & streamOut, std::basic_ios< wchar_t> & (*func)( std::basic_ios< wchar_t> &) ) { func( streamOut.underlying_stream()); return streamOut; } inline const basic_str_stream< wchar_t> & operator<< ( const basic_str_stream< wchar_t> & streamOut, std::basic_ostream< wchar_t> & (*func)( std::basic_ostream< wchar_t> &) ) { func( streamOut.underlying_stream()); return streamOut; } // END OF - allow function IO manipulators #endif // End of file ////////////////////////////////////////////////////////////////////// // example.cpp #include "str_stream.h" #include <iomanip> std::basic_ostream< wchar_t> & width_4( std::basic_ostream< wchar_t> & streamOut) { streamOut.width( 4); return streamOut; } int main() { // for wide strings. std::wstring str = wstr_stream() << std::oct << 8 << as_string(); str = wstr_stream() << std::setfill( L'0') << width_4 << 35 << std::endl << as_string(); std::wcout << str; // for strings int nUsersCount = 45; std::string s = str_stream() << "There have been " << nUsersCount << " users logged on so far"; std::cout << s << std::endl; int nWordsCount = 78; s = str_stream( "We found ") << nWordsCount << " words."; std::cout << s << std::endl; std::cin.get(); return 0; } |