Listing L
//////////////////////////////////////////////////////////////////////
// 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;
}