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::stream
is 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.