Boost logo

Boost :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2004-09-23 00:55:23


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?

> 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)]

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've
> also expeirmented with the following notation, for formatting user-defined
> types:
>
> str("Dog:") << member(dog_name)
> << ","
> << member(dog_height)
> << "]"

I'd still prefer 'serialize', just so that we have one method of describing
members.

> 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.

> 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?

- Volodya


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk