Hi All,
How do you construct an std::ostream from a
boost::iostreams::stream_buffer > ? 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_bufferio::file_sink streamBuf(sink);
std::ostream pngStream(&streamBuf);
However, I am having problems providing an ostream for the memory buffer
case.
shared_ptr vec(new vector<char>());
io::back_insert_device sink(*vec);
io::stream_buffer >
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
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.