Re: [boost] Re: Formal review of "Output Formatters"library beginstoday

John Torjo wrote:
Well, I think my alternative is better if you want a stateful change, since yours doesn't accomplish that. My suggestion is certainly consistent with normal io manipulators. The point is to stream a bunch of sequences without having to repeat the format part.
I understand what you are saying and yes your version is neater. However, implementing something like this would have performance penalties (because you will need to create/store the preset values at run-time).
The penalties are small. Anyway, using std::istream/ostream have penalties, compared to using raw FILEs ;)
This is true.
That said, in this case there shouldn't be many penalties. Again, you can use ios_base::pword and ios_base::iword for this. It's an advanced technique, but I think it can prove very neat and flexible.
okay.
It will also change the way all sequence constructs are rendered. (n-ary types have a different rendreing so won't be affected). As I understand, this is the desired effect. But then:
You can make it possible to associate a fmt object with a delimeter object.
Example: pairfmt() with openclose_formatter. basicfmt() with formatter. Etc.
That is basically what I do already: wrappedfmt() is associated with openclose_formatter; pairfmt() is associated with formatter (using default_nary_traits) containerfmt() is associated with formatter (using default_sequence_traits) etc. At the moment, default_nary_traits/default_sequence_traits provide the default strings to map to the specific type, e.g.: const char * default_nary_traits< const char * >::open_default(){ return( "( " ); } wchar_t default_nary_traits< wchar_t >::open_default(){ return( L"(" ); } std::string default_nary_traits< std::string >::open_default(){ return( std::string( "(" )); } so you can theoretically use any string type to store the default delimeter values. How do we do the equivalent with ios_base::pword/iword? openclose_formatter/formatter set their delimeter values to the values provided by the default traits object passed to them. You can then override these defaults by calling format(). How do you tell that the default has been overrided? One solution would be to use a null string as a default value. Then you can do class openclose_formatter { private: inline DelimeterType get_default_open() const { return ios_base::pword -> open(); // pseudocode } public: inline DelimeterType open() const { return( _open == null ? get_default_open() : _open ); } }; but this would complicate the access process for open(), close() and separator(), that in the current implementation simply return the data member. Also, what about string types such as std::string, QtString, CBStr and CString? What are their appropriate "null" values and how do you test that? I suppose you could have a resolve_default_values() function in the formatter class that is called when using FormatObject::read/write to reduce the resolution to a single pass, but what about when you save a formatter/format object, e.g.: io::formatter< const char * > fmt( " : " ); // oen/close use defaults std::cout << io::formatob( lst, io::containerfmt()).format( fmt ) // [1] << io::set_sequence_defaults( "< ", " >" ) // [2] << io::formatob( vec, io::containerfmt()).format( fmt ); // [3] [1] will resolve the default values used by fmt, [2] will change the defaults used and [3] will not be updated to reflect these changes, so you'd need the slower version. Alternatively, you can do this in FormatObject::read/write: DelimeterType separator_delim = separator(); while( first != last ) { // ... os << separator_delim; }
Then, you can store (default) delimeter objects within the stream. Once you want to output/input something, it requires a specific delim object. You'll somehow use ios_base::pword/iword to get a reference to that object.
The main questions are: [1] how do you store different DelimeterTypes in this mechanism? [2] how do you tell if the default is needed (see above)? Regards, Reece _________________________________________________________________ Stay in touch with absent friends - get MSN Messenger http://www.msn.co.uk/messenger

This is true.
That said, in this case there shouldn't be many penalties. Again, you can use ios_base::pword and ios_base::iword for this. It's an advanced technique, but I think it can prove very neat and flexible.
okay.
It will also change the way all sequence constructs are rendered. (n-ary types have a different rendreing so won't be affected). As I understand, this is the desired effect. But then:
You can make it possible to associate a fmt object with a delimeter object.
Example: pairfmt() with openclose_formatter. basicfmt() with formatter. Etc.
That is basically what I do already: wrappedfmt() is associated with openclose_formatter; pairfmt() is associated with formatter (using default_nary_traits) containerfmt() is associated with formatter (using default_sequence_traits) etc.
Yes, and that is great! But you hold them in the formatob object. What I'm saying is that (overridable) defaults for each of the above can also be kept in the stream object itself. That's why ios_base::iword and ios_base::pword are good for: for keeping delimeter objects *inside the stream object itself*. Thus, when you write something, and the user hasn't provided a specific delimeter, you read that delimeter from the underlying stream. (again, it's quite an advanced technique ;)) Same goes for reading.
so you can theoretically use any string type to store the default delimeter values. How do we do the equivalent with ios_base::pword/iword?
That's your job - to come up with a technique for this ;) Seriously, I'm sure it's possible (see above). Basically, the library's underlying concept doesn't have to change. This is just an extra goodie you can provide.
openclose_formatter/formatter set their delimeter values to the values provided by the default traits object passed to them. You can then override these defaults by calling format(). How do you tell that the default has been overrided?
It's certainly possible. Internally, in the delim object, you can keep the data like this: template<class value_type> struct val_keeper { value_type val; bool has_been_set; //getter and setter - I assume you get the point };
Then, you can store (default) delimeter objects within the stream. Once you want to output/input something, it requires a specific delim object. You'll somehow use ios_base::pword/iword to get a reference to that object.
The main questions are: [1] how do you store different DelimeterTypes in this mechanism?
Which brings us to ;) : I think one type of delimeter is enough (I assume you wholeheartidly disagree with this). This type should be the std::basic_string<underlying_char_type>(). This would simplify things a lot. But, in case you want multiple DelimeterTypes, it will still be possible to implement this (but only harder)
[2] how do you tell if the default is needed (see above)?
see the val_keeper above. Best, John -- John Torjo -- john@torjo.com Contributing editor, C/C++ Users Journal -- "Win32 GUI Generics" -- generics & GUI do mix, after all -- http://www.torjo.com/win32gui/ -- v1.4.0 - save_dlg - true binding of your data to UI controls! + easily add validation rules (win32gui/examples/smart_dlg)
participants (2)
-
John Torjo
-
Reece Dunn