
"Vladimir Prus" <ghost@cs.msu.su> wrote in message news:citomt$bmh$1@sea.gmane.org...
Hi Jonathan,
I see the library as the inverse of Spirit. Spirit takes a linear text and builds complex objects, while the output formatting library takes complex objects and renders them as linear text.
Interesting! Hartmut Kaiser has expressed the similar view (off-list).
II. A system for allowing user-defined type to advertise their internal structure, so that they can be accessed like the types in I. For example, a Dog class might advertise that it consists of a string name and a float weight. There are a number of ways that this could be done, such as with members-pointers, default-constuctible functors which extract the information, etc. Any combination of these techniques should be allowed.
Isn't this close to using 'serialize' for extracting members, that I advocate?
Could you repeat how this would work? I considered allowing user defined types to provide a function (member or non-member) which returns a list of members for use in serialization; unfortunately this was very wastefull in the (common) case that you don;t need to use all the information
III A framework of composable formatting objects (I'm using the term differently than the current library does) used to customize how complex types are output. A. The main building block is the concept of a Formatter (sketched below). There will be a number of built-in formatters, such as 1. sequence_formatter, for formatting objects of a type I.A.1. using specified opening, closing and separator strings 2. nary_formatter<N>, for formatting objects of a type I.A.2. Nary formatters can be specified with expression templates -- e.g.,
str("[") << _2 << " : " << _1 << ")"
would format a pair (a, b) as [b : a). (Note the reversed order.)
Wow, that's nice coincidence, here's a part of email I've sent to Hartmut yesterday:
Maybe, 'list_' should accept two parameters?
list_(';', str("(") << _1 << "," << _2)[phoenix::val(v)]
Cool.
There's still a question where do you specify the stream... but basically, the model that each formatter is just a functional object is a very simple one, and that's good.
I agree.
C. A single function boost::io::format, which takes an arbitrary type and returns an object which can be output using operator<<. Examples:
cout << boost::io::format(obj); // Uses the default style
cout << boost::io::format(obj).with(dog_format()) // Doggy-style
cout << boost::io::format(obj) // Uses a complex style .use< is_vector<_> >( sequence_format("[", ",", "]") .use< is_pair<_> >( str("(") << _1 << ":" << _2 << "]" );
Oh, MPL lambda? That's a cool idea! But isn't this a bit too flexible? At all events, the smaller the size of the headers I need to include, the better.
Maybe lamda support could be enabled at user option. Anyway, soon compilers will have mpl built in, so it should be no problem;-)
Finally, let me describe what a formatter looks like. It is a class type with a templated member function format having the following signature
template<typename Ch, typename Tr, typename T, typename Context> basic_ostream<Ch, Tr>& format(basic_ostream<Ch, Tr>& out, const T& t, Context& ctx);
Here T is the type whose instance is to be formatted, and ctx contains the prevailing Style (a combination of formatters)
If 'format' is a member of formatter, then why context should store some other formatter? Or are they formatters for nested types?
Right. A 3-ary formatter might do this (by the way, the return type should be void): template<typename Ch, typename Tr, typename T, typename Context> void format(basic_ostream<Ch, Tr>& out, const T& t, Context& ctx) { out << "<" << ctx::format(get<0>)(t) << "," << ctx::format(get<1>)(t) << "," << ctx::format(get<2>)(t) << << ">"; }
- Volodya
Jonathan