Re: IOStreams formal review start

What is your evaluation of the documentation? I've been reading through the documentation and I have a couple of questions and observations. I'm not sure I understand all the details so feel free to correct me if I've miss understood something. 1) Generally the quality of the documentation is very good. 2) I have a problem with the name of the library - I find it very misleading. I would character the library by its main functionality a) simplify the creation of new stream buffers. b) permit stream buffers to be "chained" together to sequentially process input and output. So I think a better name would be "Stream Buffer Library" Additionally it includes some very "thin" classes to make streams with with the indicated buffers. As I understand it this this basically replaces the rdbuf member of the stream in the normal way. In my view the tutorials don't make a clear distinction between stream buffers and streams. For example, I would prefer that the first one be: Defining a Stream Buffer for a New Data Source. Which would create a new stream buffer and then use in a stream created the old fashion way. Basically I think the tutorial is easier to understand if one can add one concept at a time - especially when (in my view) they are orthogonal concepts. Same for the other tutorials. The stream constructor can be in separate section. This would also make it much easier to see where the overlap is with Daryl's library. Adaptors and Object Generators Hmmm - I'm not sure "Adaptors" should be in here. How about "Streambuffer Generator" as it seems just to be shorthand for the above. Filtering Input/Output At first I was going to complain about this, but upon forming my complaint it became clear how its supposed to be used. Again I was thrown by the mixing of streambuffer and stream. I would prefer to see this divided into two pieces - making a chain of streambuffers and a final layer to used the buffer in a standard stream. It would characterize the source/sink concepts as "helpers" to building streambufs but providing the end points of a chain of filters. But that leaves me with the question "What about a filter to a standard filebuf? What do we use for sink? I'm sure its in there, I just didn't see it where I expected to find it. I presume its hidden in the filtered_?stream .. which makes harder to see. Of course this is the way its was designed so I guess I'm complaining about this design decision. 3) Reference ========= Another very professional job. A few observations: a) I'm sort of intrigued with the sequence that things are explained. For example, it's hard to understand the concept of "chains" until the Filter Stream is described. These are relatively small points. b) I'm intrigued with the section "Code Converters". How does this contrast with using a codecvt facet? What are we doing here that is not better than adding a codecvt facet? Might be better make a method of composition ("chaining") codecvt facets? I don't know the answer. As I went through that part of the documentation this question occurred to me - it sort of begs and answer. 4) Rationale a) The section Generic Design left me stumped. The selection of conditional verb tenses suggests that neither alternative was used. b) Interesting to me was that fact that the issue of streambuf vs stream is dealt with explicitly. 5) What is your evaluation of the design? a) I've already stated my reservations about the mixing of streams and stream buffers. b) the concept of "chaining" is quite different than what I would have envisioned. As I understand it, if 10 filters are chained together, this system is going to require ten levels of function calls to get a character in/out. Someone is bound to object to this. On the other hand, this system permits filter to be composed "chained" at runtime which may be useful in some instances. I would have expected something like the filters be composed at construction time with templated constructors. This would permit the inlined member functions to be collapsed by the compiler to minimize copying. The Dataflow iterators in the serialization library manifest this expection. I'm not saying that the method chosen by Jonathon isn't as good ( though I might believe that) its just not what I expected. c) I'm a little concerned as to where codecvt, wide character i/o etc fit into this. d) I would be curious as to whether this is suitable for something other than filebuf - e.g. stream adaptor for sockets i/o. ? 6) What is your evaluation of the implementation? I didn't build the library or use in any tests so I recall can't contribute to that assessment. 7) What is your evaluation of the potential usefulness of the library? This is very useful and necessary. Something like this is what I've hoped for to complement the serialization library. I envision something like this combined with the serialization libray, combined with the mult-index set as making one great in memory database. Did you try to use the library? With what compiler? Did you have any problems? no How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? A couple hours with the documentation Are you knowledgeable about the problem domain? Fairly knowledgable. Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. I have reservations as stated above. It very useful and necessary, and seems (from the quality of the documentation) a high quality implementation. If my choices were t accept or reject it as is I would accept it. Of course, if others who've studied it in more depth confirm my reservations above, I would like to see them addressed first. Robert Ramey

"Robert Ramey" <ramey@rrsd.com> wrote in message news:20040901060105.6C80331220@acme.west.net... Thanks for the review!
What is your evaluation of the documentation?
I've been reading through the documentation and I have a couple of questions and observations. I'm not sure I understand all the details so feel free to correct me if I've miss understood something.
1) Generally the quality of the documentation is very good.
2) I have a problem with the name of the library - I find it very misleading. I would character the library by its main functionality
a) simplify the creation of new stream buffers. b) permit stream buffers to be "chained" together to sequentially process input and output.
So I think a better name would be "Stream Buffer Library"
This was the original name of the library. I decided that many poeple who might benefit from using the library wouldn't be familiar enough with stream buffers to look into the library. I also thought about "Filtering Library" -- but this leaves out an important use case. "Filtering and Streaming Library" might be okay, but it might bring to mind streaming media protocols.
Additionally it includes some very "thin" classes to make streams with with the indicated buffers. As I understand it this this basically replaces the rdbuf member of the stream in the normal way.
In my view the tutorials don't make a clear distinction between stream buffers and streams. For example, I would prefer that the first one be:
Defining a Stream Buffer for a New Data Source.
Which would create a new stream buffer and then use in a stream created the old fashion way. Basically I think the tutorial is easier to understand if one can add one concept at a time - especially when (in my view) they are orthogonal concepts.
This is a good point. I believe I need to state in several prominent places that streambuf_facade and filtering_streambuf are the main components, that stream_facade and filtering_stream are provided for convenience, and that plain streams from the standard library can be used instead. I should give at least one example about how to do this. I'm not sure I like rewriting all the examples this way, since using the wrappers seems more natural.
Adaptors and Object Generators
Hmmm - I'm not sure "Adaptors" should be in here. How about "Streambuffer Generator" as it seems just to be shorthand for the above.
Hmm. It sounds like you might be looking at an old version of the library. In the new version, the relevant section is called 'STL sequence adapters.' (http://tinyurl.com/7y98b) Furthermore, under 'Planned Changes' I explain how the need for adapters will be eliminated (http://tinyurl.com/6rtkz) entirely.
Filtering Input/Output
At first I was going to complain about this, but upon forming my complaint it became clear how its supposed to be used. Again I was thrown by the mixing of streambuffer and stream. I would prefer to see this divided into two pieces - making a chain of streambuffers and a final layer to used the buffer in a standard stream.
Like this: filtering_istreambuf buf; in.push(regex_filter(regex("damn"), "darn")); in.push(zlib_decompressor()); in.push(file_source("essay.z")); istream in(&buf); // read from in. ?
It would characterize the source/sink concepts as "helpers" to building streambufs but providing the end points of a chain of filters. But that leaves me with the question "What about a filter to a standard filebuf?
std::filebuf models Sink: std::filebuf file; file.open("essay.z", std::ios::in | std::ios_binary); filtering_istreambuf buf; in.push(regex_filter(regex("damn"), "darn")); in.push(zlib_decompressor()); in.push(file); // stored by reference This is explained here, http://tinyurl.com/3qyl5, but obviously it should be stated prominently in the introduction.
3) Reference ========= Another very professional job.
Thanks.
A few observations:
a) I'm sort of intrigued with the sequence that things are explained. For example, it's hard to understand the concept of "chains" until the Filter Stream is described. These are relatively small points.
I was thinking that users would read the 'User's Guide' before the reference.Chains are explained pretty well here: http://tinyurl.com/6kccz. (esp figures 3-6). I guess everywhere I mention chains I should refer to this page.
b) I'm intrigued with the section "Code Converters". How does this contrast with using a codecvt facet?
The template boost::io::converter provides a generic implementation of code conversion using a codecvt. If you have a stream buffer implementation, such as std::filebuf, which uses a codecvt internally, then you dont need to use boost::io::converter -- you simply imbue a locale with an appropriate codecvt facet. However, many -- if not most -- stream buffer implementations do not perform any code conversion. Furthermore, if you are writing a stream buffer and want it to perform code conversion, it seriously complicates the implementation. This is what boost::io::converter is for. Say you want to write a tcpbuf that performs code conversion -- you simply write a narrow-character tcp_resource which does no conversion, then write: typedef streambuf_facade< converter<tcp_resource> > tcpbuf; This allows the library to interact with the codecvt facet, so you don't have to.
4) Rationale
a) The section Generic Design left me stumped. The selection of conditional verb tenses suggests that neither alternative was used.
Okay. In a previous version, I suggested several alternate designs, then compared them. The main alternative to generic design would be providing some base classes with virtual functions from which filters and resources have to derive. This is the approach of the Crypto++ crytographic library and the java.io package, for instance.
b) Interesting to me was that fact that the issue of streambuf vs stream is dealt with explicitly.
Could you elaborate?
5) What is your evaluation of the design?
a) I've already stated my reservations about the mixing of streams and stream buffers.
Okay.
b) the concept of "chaining" is quite different than what I would have envisioned. As I understand it, if 10 filters are chained together, this system is going to require ten levels of function calls to get a character in/out. Someone is bound to object to this. On the other hand, this system permits filter to be composed "chained" at runtime which may be useful in some instances.
I would have expected something like the filters be composed at construction time with templated constructors. This would permit the inlined member functions to be collapsed by the compiler to minimize copying. The Dataflow iterators in the serialization library manifest this expection.
It's certainly possible to make the type of filtering_streambuf depend on the types of all the filters and resources in the chain, so that there are no virtual functions except at the beginning of the chain (basic_streambuf has virtual functions) and so that all the calls to the i/o functions read, write, etc. could conceivably be inlined. However, no compiler I know of will actually inline 10 layers of non-trivial filtering. Furthermore, the cost of the function calls is largely mitigated by buffering. If buffers are large enough, the function-call overhead is minimal. (I've verified the positive effect of buffering as buffer sizes increase. The way to verify the full claim would be to write a full implementation using the alternate design and compare it with the current implementation. I'm reluctant to do this ;-) ) Finally, the principal existing implementation of filtering stream buffers, by James Kanze, works essentially the same way mine does. (See http://tinyurl.com/53ubj)
c) I'm a little concerned as to where codecvt, wide character i/o etc fit into this.
I hope I've explained this above. I'll give one more example. file_descriptor_source does not internal code conversion; it simply forwards calls to read to the appropriate low-level i/o function. If you want code conversion, you can do this: typedef streambuf_facade< converter<file_descriptor_source> > fdbuf;
d) I would be curious as to whether this is suitable for something other than filebuf - e.g. stream adaptor for sockets i/o. ?
I've used (an earlier version of) the library for socket i/o. It's one of the main envisioned use cases, and the principle reason for supporting the i/o mode 'inout' (http://tinyurl.com/5spax).
6) What is your evaluation of the implementation?
I didn't build the library or use in any tests so I recall can't contribute to that assessment.
7) What is your evaluation of the potential usefulness of the library?
This is very useful and necessary. Something like this is what I've hoped for to complement the serialization library. I envision something like this combined with the serialization libray, combined with the mult-index set as making one great in memory database.
Good.
Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
I have reservations as stated above. It very useful and necessary, and seems (from the quality of the documentation) a high quality implementation. If my choices were t accept or reject it as is I would accept it. Of course, if others who've studied it in more depth confirm my reservations above, I would like to see them addressed first.
I hope I have addressed some of your reservations. Thanks again. Jonathan

"Robert Ramey" <ramey@rrsd.com> wrote in message: Hi Robert, I've been looking over the old messages in this thread, to see if I let any important points slip by.
5) What is your evaluation of the design?
a) I've already stated my reservations about the mixing of streams and stream buffers.
b) the concept of "chaining" is quite different than what I would have envisioned. As I understand it, if 10 filters are chained together, this system is going to require ten levels of function calls to get a character in/out. Someone is bound to object to this. On the other hand, this system permits filter to be composed "chained" at runtime which may be useful in some instances.
I would have expected something like the filters be composed at construction time with templated constructors. This would permit the inlined member functions to be collapsed by the compiler to minimize copying.
I think I may have missed your point the first time through. I though you were just talking about eliminating function call overhead. Now I see that you are suggesting that copying is minimized too. How does this work?
The Dataflow iterators in the serialization library manifest this expection.
I remember when you first suggested I handle filtering (http://lists.boost.org/MailArchives/boost/msg48300.php) you mentioned an approach using iterator adapters. I decided not to use iterators because I concluded that it would miss the opportunity for many important optimizations that can be made when one is presented with a contiguous buffer full of characters instead of one character at a time. For example, I don't think zlib is very efficient if you pass it one character at a time. Still ... I wish I had looked at the Dataflow Iterators in your library when I first read your message! I put it on my mental 'to do' list then promptly forgot. It looks like Dataflow Iterators and input/output filters are intended to solve exactly the same sort of problems in many cases. So there are these obvious questions: 1. Where the functionality overlaps, which approach is faster? 2. What can your approach do that mine can't? 3. What can my approach do that yours can't? 4. If your approach is better all around, or in a broad class of cases, can I adapt my library to use it? (I think so -- the pipe notation, which you don't like, can give the compiler a clue which filters should be fused at compile time.) 5. If my approach is better, can your library use it? (BTW, How do you use the Dataflow Iterators in your library?) I'm going to try to re-implement some of your iterators as Filters, and see what happens. Best Regards, Jonathan

Jonathan, I am trying to build some of your samples with _UNICODE;UNICODE defined using Visual Studio 2003 and get a build error which is included in detail at the end of this message. Since you do not provide a Unicode sample I have modified your sample to support the Windows _TCHAR macros. The modified source code also is included at the end of this message. The code compiles and runs when _UNICODE is not defined. The build error occurs only with the Unicode build. Regards, George. Compiling... line_wrapping_example.cpp h:\source code\Turkanis\iostream\boost\io\detail\chain.hpp(169) : error C2664: 'std::list<_Ty>::push_back' : cannot convert parameter 1 from 'facade_type *' to 'boost::io::detail::linked_streambuf<Ch> & ' with [ _Ty=boost::io::detail::chain_base<boost::io::detail::chain<boost::io::output,wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>,wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>,boost::io::output>::streambuf_type * ] and [ Ch=wchar_t ] Reason: cannot convert from 'facade_type *' to 'boost::io::detail::linked_streambuf<Ch> ' with [ Ch=wchar_t ] Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast h:\source code\Turkanis\iostream\boost\io\detail\chain.hpp(134) : see reference to function template instantiation 'void boost::io::detail::chain_base<Self,Ch,Tr,Alloc,Mode>::push_impl<T>(const T &,std::streamsize,std::streamsize)' being compiled with [ Self=boost::io::detail::chain<boost::io::output,wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>, Ch=wchar_t, Tr=std::char_traits<wchar_t>, Alloc=std::allocator<wchar_t>, Mode=boost::io::output, T=boost::io::example::line_wrapping_output_filter ] h:\source code\Turkanis\iostream\boost\io\detail\chain.hpp(317) : see reference to function template instantiation 'void boost::io::detail::chain_base<Self,Ch,Tr,Alloc,Mode>::push<T>(const T &,std::streamsize,std::streamsize,boost::disable_if_c<B,void>::type *)' being compiled with [ Self=boost::io::detail::chain<boost::io::output,wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>, Ch=wchar_t, Tr=std::char_traits<wchar_t>, Alloc=std::allocator<wchar_t>, Mode=boost::io::output, T=boost::io::example::line_wrapping_output_filter, B=false ] h:\source code\Turkanis\iostream\boost\io\detail\chain.hpp(310) : see reference to function template instantiation 'void boost::io::detail::chain_client<Chain>::push_impl<T>(const T &,std::streamsize,std::streamsize)' being compiled with [ Chain=boost::io::detail::chain<boost::io::output,wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>, T=boost::io::example::line_wrapping_output_filter ] h:\Projects\Turkanis\example\line_wrapping_example\line_wrapping_example.cpp(46) : see reference to function template instantiation 'void boost::io::detail::chain_client<Chain>::push<boost::io::example::line_wrapping_output_filter>(const T &,std::streamsize,std::streamsize,boost::disable_if_c<B,void>::type *)' being compiled with [ Chain=boost::io::detail::chain<boost::io::output,wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>, T=boost::io::example::line_wrapping_output_filter, B=false ] //line_wrapping_output_filter.hpp #ifndef BOOST_IO_EXAMPLE_LINE_WRAPPING_OUTPUT_FILTER_HPP_INCLUDED #define BOOST_IO_EXAMPLE_LINE_WRAPPING_OUTPUT_FILTER_HPP_INCLUDED #include <boost/io/concepts.hpp> // output_filter. #include <boost/io/operations.hpp> // boost::io::put. namespace boost { namespace io { namespace example { class line_wrapping_output_filter : public output_filter { public: explicit line_wrapping_output_filter(int line_length = 80) : line_length_(line_length), col_no_(0) { } template<typename Sink> void put(Sink& dest, int c) { if (c == __T('\n')) col_no_ = 0 ; else { if (col_no_ >= line_length_) this->put(dest, __T('\n')); ++col_no_ ; } boost::io::put(dest, c); } template<typename Sink> void close(Sink& dest) { boost::io::put(dest, __T('\n')); col_no_ = 0; } private: int line_length_ ; int col_no_; }; } } } // End namespaces example, io, boost. #endif // #ifndef BOOST_IO_EXAMPLE_LINE_WRAPPING_OUTPUT_FILTER_HPP_INCLUDED //line_wrapping_filter.cpp #include <windows.h> #include <tchar.h> #include <iostream> #include <boost/io/filtering_stream.hpp> #include "line_wrapping_output_filter.hpp" #ifdef _UNICODE #define filtering_tostream filtering_wostream #define _tcout wcout #else #define filtering_tostream filtering_ostream #define _tcout cout #endif //_UNICODE // // Demonstrates the use of line_wrapping_output_filter. // void test_line_wrapping() { using namespace std; using namespace boost::io; using namespace boost::io::example; const _TCHAR* text = __T("In the country of Westphalia, in the castle of the most noble Baron ") __T("of Thunder-ten-tronckh, lived a youth whom Nature had endowed with a ") __T("most sweet disposition. His face was the true index of his mind. He ") __T("had a solid judgment joined to the most unaffected simplicity; and ") __T("hence, I presume, he had his name of Candide. The old servants of the ") __T("house suspected him to have been the son of the Baron's sister, by a ") __T("very good sort of a gentleman of the neighborhood, whom that young ") __T("lady refused to marry, because he could produce no more than ") __T("threescore and eleven quarterings in his arms; the rest of the ") __T("genealogical tree belonging to the family having been lost through ") __T("the injuries of time....\n"); filtering_tostream out; out.push(line_wrapping_output_filter(50)); out.push(_tcout); // Print unfiltered text. _tcout << __T("**** Candide ****\n\n") << text << __T("\n\n"); // Print filtered text: out << __T("**** Candide with line wrapping ****\n\n") << text << __T("\n\n"); } int _tmain() { test_line_wrapping(); return 0; }

Johnathan, Funny. It works if I templatize line_wrapping_output_filter like so: template<class CHAR_TYPE> class line_wrapping_output_filter : public output_filter { public: typedef CHAR_TYPE char_type; explicit line_wrapping_output_filter(int line_length = 80) : line_length_(line_length), col_no_(0) { } template<typename Sink> void put(Sink& dest, int c) { if (c == char_type('\n')) col_no_ = 0 ; else { if (col_no_ >= line_length_) this->put(dest, char_type('\n')); ++col_no_ ; } boost::io::put(dest, c); } template<typename Sink> void close(Sink& dest) { boost::io::put(dest, char_type('\n')); col_no_ = 0; } private: int line_length_ ; int col_no_; }; Regards, George.

"George M. Garner Jr." <gmgarner@erols.com> wrote in message news:chqhec$j0g$1@sea.gmane.org...
Johnathan,
Funny. It works if I templatize line_wrapping_output_filter like so:
template<class CHAR_TYPE> class line_wrapping_output_filter : public output_filter
Right -- I was just getting around to answering your message. Most of the filters included with the core library are templatized on character type. The examples use char for simplcity. If you want to use TCHAR, that should be fine, as long as you specify it as a template parameter everywhere. (You might run into trouble if you use /Zc:wchar_t, I'm not sure.) If I include a version of the line-wrapping filter as a real part of the library, I'll make sure to templatize it. But there are other questions, too, such as what the policy for breaking words should be. Best Regards, Jonathan

Johnathan, Actually, the problem was that line_wrapping_output_filter needs to derive from output_wfilter not output_filter for Unicode applications. The code that I posted previously derives line_wrapping_output_filter<__wchar_t> from output_filter. The fact that this compiles and works is problematic because it introduces a certain ambiguity that may bite in the future.
(You might run into trouble if you use /Zc:wchar_t, I'm not sure.)<
That's only a problem if you compile the library with a different setting than the application to which it is linked. I have tried it both ways without problem. There is a bug in regex_filter.hpp line 58: basic_regex_filter( const regex_type& re, -- const char* fmt, // ++ const char_type* fmt, flag_type flags = regex_constants::match_default, flag_type fmt_flags = regex_constants::format_default ) Regards, George.

"George M. Garner Jr." <gmgarner@erols.com> wrote in message news:chqr6i$ifu$1@sea.gmane.org...
Johnathan,
Actually, the problem was that line_wrapping_output_filter needs to derive from output_wfilter not output_filter for Unicode applications. The code that I posted previously derives line_wrapping_output_filter<__wchar_t> from output_filter. The fact that this compiles and works is problematic because it introduces a certain ambiguity that may bite in the future.
Like I said, this example was not meant for production use. It was designed as a simple example of a narrow-character filter.
(You might run into trouble if you use /Zc:wchar_t, I'm not sure.)<
That's only a problem if you compile the library with a different setting than the application to which it is linked. I have tried it both ways without problem.
That's good to know.
There is a bug in regex_filter.hpp line 58:
basic_regex_filter( const regex_type& re, -- const char* fmt, // ++ const char_type* fmt, flag_type flags = regex_constants::match_default, flag_type fmt_flags = regex_constants::format_default )
Good catch!
Regards,
George.
Jonathan

Johnathan, Actually, I think that this is a design flaw. The fact that line_wrapping_output_filter<__wchar_t> derived from output_filter both compiles and runs means that the template character type is being derived using *implicit* rules that may not always lead to the intended result. There should be no ambiguity about character type given the central role that character type plays in template selection. What you really need is to *explicity* pass character type as a template argument. Thus output_filter and output_wfilter should be output_filter<char_type>. Ambiguities tend to bite you in the ass sooner or later. Regards, George. "Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:chqsii$kur$1@sea.gmane.org...
"George M. Garner Jr." <gmgarner@erols.com> wrote in message news:chqr6i$ifu$1@sea.gmane.org...
Johnathan,
Actually, the problem was that line_wrapping_output_filter needs to derive from output_wfilter not output_filter for Unicode applications. The code that I posted previously derives line_wrapping_output_filter<__wchar_t> from output_filter. The fact that this compiles and works is problematic because it introduces a certain ambiguity that may bite in the future.
Like I said, this example was not meant for production use. It was designed as a simple example of a narrow-character filter.
(You might run into trouble if you use /Zc:wchar_t, I'm not sure.)<
That's only a problem if you compile the library with a different setting than the application to which it is linked. I have tried it both ways without problem.
That's good to know.
There is a bug in regex_filter.hpp line 58:
basic_regex_filter( const regex_type& re, -- const char* fmt, // ++ const char_type* fmt, flag_type flags = regex_constants::match_default, flag_type fmt_flags = regex_constants::format_default )
Good catch!
Regards,
George.
Jonathan
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"George M. Garner Jr." <gmgarner@erols.com> wrote in message news:chsoo1$nsd$1@sea.gmane.org...
Johnathan,
Actually, I think that this is a design flaw. The fact that line_wrapping_output_filter<__wchar_t> derived from output_filter both compiles and runs means that the template character type is being derived using *implicit* rules that may not always lead to the intended result.
I didn't look at your example closely enough. Let me quote the relevant part: "George M. Garner Jr." <gmgarner@erols.com> wrote:
template<class CHAR_TYPE> class line_wrapping_output_filter : public output_filter { public: typedef CHAR_TYPE char_type;
The problem is here ^^^^^^^ The point of deriving from the convenience base classes is that you don't have to specify the char_type and category. Here the category inherited from output_filter is correct, and you've hidden the incorrect inherited char_type. If you want to define a filter templated on the char type, you should inherit from the class template filter (http://tinyurl.com/5o8uh): template<typename Ch> class line_wrapping_output_filter : filter<output, Ch> { ... }; the typedefs typedef filter<input> input_filter; typedef filter<output> output_filter; typedef wfilter<input> input_wfilter; typedef wfilter<output> output_wfilter; are supposed to represent the most commonly used specializations of filter.
There should be no ambiguity about character type given the central role that character type plays in template selection. What you really need is to *explicity* pass character type as a template argument. Thus output_filter and output_wfilter should be output_filter<char_type>. Ambiguities tend to bite you in the ass sooner or later.
I tend to think this is a problem with my documentation: I should give at least one prominent example where I use the templated base classes filter and resource. Your thoughts?
Regards,
George.
Jonathan

Jonathan,
The problem is here ^^^^^^^ <
Chain.hpp includes code at line 292 that derives the character type from, in effect, the most derived class: typedef typename chain_type::char_type char_type; This yields correct results provided you are consistent in doing this. You might want to include something like this in your samples since an ounce of prevention is worth a pound of cure: STATIC_CHECK(sizeof(char_type) == sizeof(typename output_filter::char_type), Error_char_type_mismatch_with_base_class) Also, one good Unicode sample will accomplish more than many pages of documentation. The samples should show how to accomplish common programming tasks. Regards, George.

"George M. Garner Jr." <gmgarner@erols.com> wrote in message news:cht154$fsl$1@sea.gmane.org...
Jonathan,
The problem is here ^^^^^^^ <
Chain.hpp includes code at line 292 that derives the character type from, in effect, the most derived class:
Right, that's what it's supposed to do.
This yields correct results provided you are consistent in doing this. You might want to include something like this in your samples since an ounce of prevention is worth a pound of cure:
STATIC_CHECK(sizeof(char_type) == sizeof(typename output_filter::char_type), Error_char_type_mismatch_with_base_class)
Could you be more specific? There are many places in the source where I use static asserts to make sure character types match. The problem with your previous example is that you were misusing the base class (I don't blame you -- I blame the docs) It's as if you were to write: struct printer : std::unary_function<int, void> { typedef int result_type; int operator() (int n) const { std::cout << n; } }; This is an incorrect use of std::unary_function.
Also, one good Unicode sample will accomplish more than many pages of documentation. The samples should show how to accomplish common programming tasks.
Quite right.
Regards,
George.
Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:cht2bi$jo7$1@sea.gmane.org...
This was just a dumb example, but I may as well correct it:
struct printer : std::unary_function<int, void> { typedef int result_type; int operator() (int n) const { std::cout << n; }
int operator() (int n) const { std::cout << n; return 0; }
};
Jonathan

Johnathan,
Could you be more specific? There are many places in the source where I use static asserts to make sure character types match. <
I am referring to the six samples provided with the source, only five of which derive a class from input_filter or output filter. Perhaps the better approach would be, in the samples, to derive from filter<input, char> or filter<output, char> instead of input_filter or output_filter. You could note in a comment that input_filter, input_wfilter, output_filter and output_wfilter are short hand for filter<input, char>, filter<input, __wchar_t>, filter<output, char> and filter<output, __wchar_t>, respectively. One good sample is worth many pages of documentation. Regards, George. P.S. Sorry about the subject line but at this point I have no idea of what it should be.

"George M. Garner Jr." <gmgarner@erols.com> wrote in message news:chvmb0$heb$1@sea.gmane.org...
Johnathan,
Could you be more specific? There are many places in the source where I use static asserts to make sure character types match. <
I am referring to the six samples provided with the source, only five of which derive a class from input_filter or output filter.
In these examples, static asserts wouldn't help. Generally they are useful to make sure that the character types of two template parameters are compatible.
Perhaps the better approach would be, in the samples, to derive from filter<input, char> or filter<output, char> instead of input_filter or output_filter. You could note in a comment that input_filter, input_wfilter, output_filter and output_wfilter are short hand for filter<input, char>, filter<input, __wchar_t>, filter<output, char> and filter<output, __wchar_t>, respectively. One good sample is worth many pages of documentation.
I agree whole-heartedly with the last statement. The reason I used input_filter or output_filter as the base class for all the examples is because I thought it would be the typical use case. Now I think making about half of them wide-character would be a good idea. Rather than using filter<input, char>, e.g., in the examples, I'd rather add a link to the docs for filter, where I am now planning to add some examples.
Regards,
George.
P.S. Sorry about the subject line but at this point I have no idea of what it should be.
I think my mail client is to blame. Jonathan

Over the course of this thread, the subject line has changed from: Re:Unable to build line_wrapping_output_filter with _UNICODE defined (was: IOStreams formal review start) to Re: Unabletobuildline_wrapping_output_filterwith_UNICODEdefined I've noticed this happening in several other threads. Aside from being a bit rude, these changes mess up archiving and searching. I'm sure nobody's doing this on purpose -- it must be a "helpful" feature of some email software -- but it really ought to stop if possible. Please take a moment to see if your mailer is responsible and take steps to fix the problem. Thank you, Dave -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uoekdp00o.fsf_-_@boost-consulting.com...
Over the course of this thread, the subject line has changed from:
Re:Unable to build line_wrapping_output_filter with _UNICODE defined (was: IOStreams formal review start)
to
Re: Unabletobuildline_wrapping_output_filterwith_UNICODEdefined
I see that my replies have initiated some of these fusions. This is odd, since I have just been using the subect lines generated by my newreader.
I've noticed this happening in several other threads. Aside from being a bit rude,
Bothersome, maybe.
these changes mess up archiving and searching. I'm sure nobody's doing this on purpose -- it must be a "helpful" feature of some email software -- but it really ought to stop if possible. Please take a moment to see if your mailer is responsible and take steps to fix the problem.
Okay.
Thank you, Dave
Jonathan
participants (4)
-
David Abrahams
-
George M. Garner Jr.
-
Jonathan Turkanis
-
Robert Ramey