Boost logo

Boost Users :

Subject: [Boost-users] Conditions for casting stream_buffer to std::basic_streambuf
From: Tyler Weston (tyler.weston_at_[hidden])
Date: 2011-02-22 16:18:32


Hi All,

How do you construct an std::ostream from a
boost::iostreams::stream_buffer<io::back_insert_device<...> > ? Is this not
possible with a simple sink_tag for the category?

I'm using libpng and want to abstract writing to a file directly or to a
memory buffer. libpng provides hooks for write and flush functions, and
never seeks. I implemented these functions for std::ostream and it works
great for file writing. My assumption that it would be trivial to provide a
std::ostream to a memory buffer turned out to be incorrect.

Unfortunately type information is lost through libpng as you have to pass
your io data as void*, which makes using templatized stream classes
difficult. In the tutorial for iostreams it says: "The template
io::streamis provided as a convenience. It's always possibly to avoid
io::stream and simply use io::stream_buffer together with one of the
standard library stream templates."

I tried following this pattern, and it works great for files:

        io::file_sink sink(filename, std::ios_base::out |
std::ios_base::trunc | std::ios_base::binary);
        io::stream_buffer<io::file_sink> streamBuf(sink);
        std::ostream pngStream(&streamBuf);

However, I am having problems providing an ostream for the memory buffer
case.

        shared_ptr<vector<char> > vec(new vector<char>());
        io::back_insert_device<vector<char> > sink(*vec);
        io::stream_buffer<io::back_insert_device<vector<char> > >
streamBuf(sink);
        std::ostream pngStream(&streamBuf);

This snippet produces the following error in msvc 9 with boost 1.45.

2>error C2664:
'std::basic_ostream<_Elem,_Traits>::basic_ostream(std::basic_streambuf<_Elem,_Traits>
*,bool)' : cannot convert parameter 1 from
'boost::iostreams::stream_buffer<T> *' to
'std::basic_streambuf<_Elem,_Traits> *'
2> with
2> [
2> _Elem=char,
2> _Traits=std::char_traits<char>
2> ]
2> and
2> [
2> T=boost::iostreams::back_insert_device<std::vector<char>>
2> ]
2> and
2> [
2> _Elem=char,
2> _Traits=std::char_traits<char>
2> ]
2> Types pointed to are unrelated; conversion requires
reinterpret_cast, C-style cast or function-style cast

I noticed file_sink::category has more tags than
back_insert_device::category, so I took the container_device in the tutorial
and implemented all the tags that file_sink has, and still get the same
error. Digging farther I see that basic_file::impl contains an actual
std::basic_filebuf which can be casted to basic_streambuf. The basic_filebuf
is private member of a private member, so shouldn't be accessible for normal
casting and I don't see the cast explicitly provided. How does the file_sink
to basic_streambuf cast work? How can I implement this cast for
container_device without inheriting and overriding all of the methods of
basic_streambuf?

 Is there an abstract parent class to boost::iostreams::stream or
stream_buffer that allows for polymorphism to ease the pain of the required
void* cast? I'm still relatively new to metaprogramming patterns.

As a side note, the tutorial continues to suggest default-constructing a
std::ostream, which is not possible at least with msvc's std implementation.



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net