Boost logo

Boost :

From: Reece Dunn (msclrhd_at_[hidden])
Date: 2004-09-21 05:25:31


Rozental, Gennadiy wrote:
>Here some question I've got while reading submitted library.
>
>1. What is an advantage if using this library for scalar types (vs.
>defining
>operator<<)

Do you mean for things like int, Person, etc. If that is the case, the
default behaviour of the library is to delegate output of these types to
operator<<, so it doesn't do much. However, with support for a
fmt::serialize formatter that calls 'serialize' instead of <<, you can
register a particular class as being serializable so my type deduction
system knows to associate instances of that type with fmt::serialize, so you
can then do:

   // new design
   std::cout << io::object( my_serializable_object ) << '\n';
   std::cout << io::object( vec_of_serializable_objects ) << '\n'; // [ ...,
..., ... ]

The advantage of using this for things like std::complex or
boost::math::quaternion that already supply << and >> operators is if you
want to have control over how a type is rendered, e.g.:

   // new design
   std::cout << io::object( complex_val ).decorate( "", "", " + i" )
      << " = " << io::object( complex_val ).decorate( "( ", " )" ) << '\n';

>2. If primary target is collection formatting wouldn't it be better to name
>library "collection formats something"?

This is a good idea. The name is from when the library just had output
support, thus the "outfmt" directory in the sandbox. I am thinking about
moving to a "formatter" directory. What do other people think?

>3. If there is a way to assign format to collection/type combination
>permanently (through global operator <<), why would I want to do it in
>every
>instance of output operation?

Do you mean:
   std::vector< int > vec;
   std::cout << "vector = " << vec << '\n'; // [1]
   std::cout << "vector = " << io::formatob( vec ) << '\n'; // [2]

using [1] vs using [2]? If so, these are the same, but the second allows you
to customize the decoration around the sequence, for example:

   std::cout << io::formatob( vec ).format( " : " ); // [ 1 : 2 : 3 : 4 ]

>4. What is an advantage of using this library to assign format to
>collection/type combination permanently vs. explicit implementation (using
>FOREACH construct for example)

Using a foreach construct you would need to hand-code the surrounding
decoration, e.g.:

   // output: { a + b + c }
   std::cout << "{ ";
   foreach( char ch : vec )
   {
      std::cout << ch;
      if( !atend ) std::cout << " + ";
   }
   std::cout << " }";

vs:

   std::cout << io::formatob( vec ).format( "{ ", " }", " + " ); // output:
{ a + b + c }

If you have a nested construct, such as int tictactoe[ 3 ][ 3 ], std::list<
std::list< float > > or math::matrix4x4< float > then outputting/inputting
it manually would be more complex, whereas my library has all the machinery
to handle this simply.

>5. Why do we need boost::io::range? Couldn't we use boost::range instead?

I suppose it would be possible to use boost::range::make_iterator_range
instead. The only thing I have against this is its length. Consider:

   // new design
   using boost::range::make_iterator_range;
   namespace range = boost::range;
   namespace io = boost::io;

   std::cout << io::object( range::make_iterator_range( i, i + 7 )); // [1]
   std::cout << io::object( make_iterator_range( i, i + 7 )); // [2]
   std::cout << io::object( io::range( i, i + 7 )); // [3]

If only you could alias functions, e.g.:
   namespace io{ alias range = boost::range::make_iterator_range; }

>6. In a formatter usage how would I guess what is what?
> boost::io::formatter< char * > fmt( "\ ", " /", " | " );
> boost::io::formatob( vec, boost::io::containerfmt()).format( fmt );

I have revised the names, so that is now:
   namespace fmt = boost::io::format;

   io::sequence_decorators< char > seq( "\\ ", " /", " | " );
   io::object( vec, fmt::container()).decorate( seq );

>7. Who come format calls order dependent?
> boost::io::formatob( vec, boost::io::containerfmt()).format( fmt
>).format(
>" : " );

format( fmt ) is called first, then format( " : " ). Thus, you will have "\
a : b : c /" as the formatting.

>8. If I got vector<vector<int> >. How do I supply separators for both
>internal and external vectors?

You apply the 'format' function to containerfmt(). For example:
   boost::io::formatob( vec, containerfmt( containerfmt().format( " : "
)).format( " + " ));
   // output: [ [ a : b : c ] + [ x : y : z ] + ... ]

>9. Let say I print vector<char>. Is there way to print it like this: { 'a',
>'b', '0x01', ' ' }

Yes. You need to provide a wrappedfmt() format object. For example:

   formatob( vec, containerfmt( wrappedfmt().format( "'", "'" ))).format( "{
", " }" );
   // output: { 'a', 'b', 'c' }

With the 0x01 character, special treatment needs to be applied. You will
need to supply a custom format object to see if the character is printable,
e.g.:

class char_escape
{
   public:
      typedef void traits_type;
      typedef const char * format_type;
      typedef boost::io::seq_type< -1 > formatter_type;
   public:
      template< typename CharT, typename TraitsT >
      static std::basic_ostream< CharT, TraitsT > &
         write( std::basic_ostream< CharT, TraitsT > & os, CharT value )
const
      {
         if( isprintable( value )) return( os << value );
         return( os << "0x" << int( value ));
      }
};

   formatob( vec, containerfmt( wrappedfmt( char_escape()).format( "'", "'"
))).format( "{ ", " }" );
   // output: { 'a', 'b', 'c' }

Regards,
Reece

_________________________________________________________________
Use MSN Messenger to send music and pics to your friends
http://www.msn.co.uk/messenger


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