
On Thursday 28 October 2004 12:26, Reece Dunn wrote:
Hi All,
I have been working on the library and have got a local reimplementation of my Output Formatters library based on the review comments. There are still a few issues that need to be resolved and I would like to expand stream state support.
I have created a preliminary evolution document available at: http://uk.geocities.com/msclrhd/iocoll/evolution.html that outlines what the new functionality looks like. This redesign addresses several of the issues brought up during the review.
Hi Reece, here are my comments on the design.
Use () if you want to get the value of a decoration:
sep() == "|"; // instrinsinc value
Why would I want to do this?
sep( std::cout ) == "|"; // stream default if sep() == std::string()
So, this means: 'value in sep if any, otherwise value in stream'?
If you want to see if a decorator is on an input stream, you can use match:
io::match( std::cin, sep );
What are the use cases for this?
boost::io::wrapper_decorators< CharT, RetType = void >
While I see why it's called "wrapper", the name still sounds a bit strange for me. Maybe, "open_close_decorators"?
Holds an (open, close) decorator set.
boost::io::wrapper_decorators< char > wrap( "< ", " >" ); boost::io::wrapper_decorators< char > wrap2( wrap );
wrap.decorate( "[[ ", " ]]" ); wrap2.decorate( wrap );
Why do I need the 'decorate' method as opposed to wrap = wrapper_decorators<char>("<", ">") or wrap.assign("[[", "]]") The idea that I can decorate a decorator does not seems good for me. Why do I need to change decorators in this way? To change them, I need to access decorators stored on the stream. How do I do that?
RATIONALE: RetType -- a class may derive from this class and you may want to chain function calls. For example:
derived_class dc; dc.decorate( "/ ", " /" ).derived_fn();
RetType is needed to allow this type of behaviour.
Do you have the need for it at the moment? If not, I suggest you drop this template argument. I had something similar in program_options and was messy, did not work everywhere and added no value.
[3]: sequence decorators
boost::io::sequence_decorators< CharT, RetType = void >
Holds an (open, close, separator) decorator set. Derives from wrapper_decorations.
io::sequence_decorators< char > seq1; io::sequence_decorators< char > seq2( " : " ); io::sequence_decorators< char > seq3( "( ", " )" ); io::sequence_decorators< char > seq4( "[ ", " ]", " | " ); io::sequence_decorators< char > seq5( wrap );
Do I ever need to use this constructor?
===== TYPE TRAITS AND INTROSPECTION
[4] type traits
The type traits unit consists of a series of identifiers (basic_type, array_type, etc.) that mark a specific class/template as belonging to that generic class. This allows you to manipulate a generic template type based on it's generic classification.
RATIONALE: This allows the input/output algorithms to be written without knowing the underlying template type, so the algorithms can support additional class/template types without modifying the code.
Fully agree with this.
In order to tell the framework about a type, you need to register it using:
BOOST_IO_CLASSIFY_TYPE( nargs, tempate_type, type_class )
where nargs is the number of template arguments the class has template_type is the name of the class (e.g. std::list) template_class is the type to which the class belongs (e.g. boost::io::seq_container_type)
BOOST_IO_CLASSIFY_TYPE( 1, std::complex, io::nary2value_type );
Cool.
[5] boost::io::is_XXX< T >
These MPL objects assert whether T is of type XXX, e.g.:
Cool.
[6] n-ary objects
An n-ary object (currently, 2-ary, 4-ary and 8-ary objects are supported) is a statically-sized sequence of n elements. There is support here for describing how one of these types is constructed and for manipulating its elements.
In order to get the nth element of an n-ary object ob, you can use getval:
std::cout << io::getval< n >( ob ) << '\n';
Isn't 'getval' an implementation detail of the library?
BOOST_IO_NARY_PARAM2 is used to register a 2-ary type as containing two different types for elements 1 and 2, e.g. std::pair. BOOST_IO_NARY_PARAM1 is used in all other cases.
BOOST_IO_NARY_PARAM2( std::pair, seperable_pair ) BOOST_IO_NARY_PARAM1( std::complex, inseperable_pair< T > )
And what about 4-ary objects? Still BOOST_IO_NARY_PARAM1? What if there are 4 different template parameters?
This is implemented like this:
template< int n, typename T1, typename T2 > typename io::detail::selector< n, T1, T2 >::ref_type io::refval( std::pair< T1, T2 > & p ) { return( detail::selector< n, T1, T2 >::ref( p.first, p.second )); }
where the ref function of detail::selector takes 2, 4 or 8 arguments and returns a reference to the nth argument.
An inseperable pair (io::inseperable_pair< T1, T2 = T1 >), 4-ary (io::nary4_type< T >) or 8-ary (io::nary8_type< T >) object cannot obtain a reference to individual elements. They need to be set at the same time using io::assignval:
io::assignval( ob2ary, a, b ); io::assignval( ob4ary, a, b, c, d ); io::assignval( ob8ary, a, b, c, d, e, f, g, h );
I think you're again discussing implementation, not interface. I don't think this function should be initially present in the library public interface.
[7] automatic type deduction
The fmt::deduce function:
template< typename CharT, typename T > [undefined] fmt::deduce( const T & ob );
will return an instance to the nested format object construct that maps to the class T.
Ok, we've got to interesting part. I don't understand what's "nested format object", what's "construct", and what does it mean for "construct" to map to some class. And you haven't defined "format object" yet.
The deduction mechanism involves registering the format object with a type class.
Maybe, you should call that "type category" to avoid confusion.
In order to save writing code when several types are implemented by a format object, you can map these types into a formatter class type:
SEQ_TYPE_TO_FORMATTER( nary2value_type, pair_type ); SEQ_TYPE_TO_FORMATTER( nary2base_type, pair_type ); SEQ_TYPE_TO_FORMATTER( nary2int_type, pair_type );
This means that any nary2xxx type is formatted as a pair_type. The class
Hmm... what's nary2int_type, nary2base_type and nary2value_type? I though there's only one type category for n-ary objects, now I see two more. that
extracts the format object information for a type is looked up internally using:
fmt::detail::get_deducer< CharT, T >::type
As a user, you don't need this, but if you are adding a format object into the type deduction framework, you will need this to extract the nested format object.
Could you rephrase the above? I did not understand anything. Maybe, part of confusion is the use of "decuder" which you did not define. The word "deducer" automatically brings "template argument deduction" phrase for me and don't know how it's related to 'deducer' that you use.
A format object is deduced by defining fmt::detail::deduce_type for the formatter class type
What's "formatter class type"? Is that "type category"?
that the format object handles. It has the form:
Say I've used SEQ_TYPE_TO_FORMATTER( nary2value_type, pair_type ) already. Do I need to define this?
template<> struct fmt::detail::deduce_type< type > { template< typename CharT, typename T >
What's 'T' here? The type being output?
[8] format object generators
The format objects provided by the library supply generator functions to simplify the creation of format objects.
A generator gen will have the form gen< CharT >() to specify the character type used by the format object to store the decoration values. It will have the form gen() that is equivalent to gen< char >().
Such overloads (non-template + template) used to cause problems for me. IIRC, on borland.
In addition, the format object may provide additional forms to allow format object nesting.
I did not understood what's generator and when it should be used.
[9] format objects
A format object is a class that tells the I/O collection framework how to render an object to/from a stream.
In order to read an object in from a stream, it implements the read function that takes the stream (is) being used as the input source and the object (ob) to read into. It has the form:
std::basic_istream< CharT, TraitsT > & read( std::basic_istream< CharT, TraitsT > & is, T & ob ) const;
In order to write an object out to a stream, it ipmlements the write function that takes the stream (out) being used as the output source and the object (ob) that is being written to the stream. It has the form:
std::basic_ostream< CharT, TraitsT > & write( std::basic_ostream< CharT, TraitsT > & os, const T & ob ) const;
Ok, this is reasonable.
<1> basic format object
fmt::basic_t< CharT > is the default format object that renders the object using the << and >> operators. The generator function is fmt::basic().
<2> pair format object
fmt::pair_t< CharT, First, Second > will render 2-ary object types using First to render the first element and Second to render the second. The generator function is fmt::pair() and has the additional form:
[unspecified] fmt::pair( const First & f, const Second & s = basic());
<7> state format object
fmt::state_t< CharT, StateObject, bool pre, FO > will render the state object defined by StateObject before the object being read or written if pre is
"unspecified"? Shouldn't that be fmt::pair_t<charT, First, Second>? And BTW, I'm strongly against the "_t" suffix. Does it add any information or you just _t because 'pair' is already used? What about calling the type "pair_formatter"? And, why do I ever need to create the formatter explicitly? Can I call any methods of it? true. I think the name "state format" is a bit unclear. I'd suggest some more explicit pre_format_hook/post_format_hook, or something like that. BTW, some thinks (and I'd agree) that using 'bool' as parameter to function/template is not good. If I look at state<Foobar, true>() I have no idea what 'true' means.
<8> object manipulator
io::object_t< CharT, T, FO > is a special type of format object in that it provides I/O manipulator functionality
What's "I/O manipulator functionality"? Do you mean stream insertion/extraction operators? It's quite different from manipulators, which only change stream properties, don't output anything. Finally: you mentioned you have revised version of the code. Looks like it's not in sandbox. Is it possible to take a look? - Volodya