Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2003-03-17 17:10:46


>From: "Jason House" <jhouse_at_[hidden]>

> Terje Slettebø wrote:
> > typedef std::vector<char> vector_char;
> >
> > vector_char values;
> >
> > // Fill with 'A', 'B', 'C'
> >
> > std::cout << io::format<vector_char>("[", "]", ", ", "\'", "\'") <<
values;
> >
> > Output:
> >
> > ['A', 'B', 'C']
> >
> > However, is this overkill?
>
> It seems that way, especially considering that if it was a vector of
> anything other than a fundamental type with std::cout << already defined
> for it, you could add a second io::format<char>("\'","\'","") and it
> would work.

Right. However, I've already implemented it, anyway, as an experimental
feature. :) Besides, the two extra strings default to empty strings.

> > Feedback is most welcome.
>
> Would possibly a function object for outputting the contained item be
> better?

[I first thought you meant a function object for outputting the _container_,
not the elements, so I wrote the following section, before realising that
you had meant for the elements. I address it afterwards]

I've been thinking of the same, with regard to outputting the _container_
(not the element, itself). In an earlier posting, I mentioned the
possibility of using function objects, as a way to generalising the handling
of output. I also mentioned having the kind of function objects like BGL,
i.e. "visitors". That is, rather than only overloading the operator(), it
may provide several member functions, e.g.:

class stream_visitor
{
public:
  void start();
  void end();
  void delimiter();
};

std::cout << format<type>(stream_visitor(...));

One could then provide a function object which does what it currently does.

There are issues with this, however. I've been thinking long and hard about
how to provide this functionality. The issue is that the functors has to be
stored somewhere, and being accessible. With the current version, all the
format objects are the same type, so you know its type when it's stored and
retrieved. However, if arbitrary (generic) functors are stored, you don't
know its type, when you access it, when performing output. It's similar to
trying to store different types in the same std::vector.

There are solutions to this, and one is to use a common interface, and all
functors inherit from that interface, and override the virtual functions.
That would let you store them using a pointer to the interface. However,
this means the overhead of a virtual function call per call to the member
functions above. This may not be that much, but it's still also the issue
that generic functors can't be used - they all have to inherit from the same
interface.

For this reason, I found that this could be a possible later addition, if we
find that the added flexibility is worth it.

Also, the current syntax could still be kept as a convenience, by having an
overloaded constructor taking the strings, and creating the functor. So a
change may be backwards compatible.

> Here's a possibly mutilated example (I've never actually used
> function objects before):
>
> std::ostream delimitted_char(std::ostream out, char x, std::string
> first, std::string last);
>
> std::cout << io::format<vector_char>("[", "]", ", ",
> bind("\'", 4, bind("\'", 3, delimitted_char)))

Yes, it's possible, but I this seems to make it more complex than simply
using io::format<vector_char>("[", "]", ",", "\'", "\'"), with the two last
strings defaulted to empty strings.

> > There's yet another alternative way this may be done, using
"placeholder"
> > types, i.e.:
> >
> > std::cout << io::format<std::vector<_> >(...); // Sets the format for
all
> > vectors
> > std::cout << io::format<_>(...); // Sets the format for all types
(defaults)
> >
> > This would avoid hardcoding any defaults, as the user could change it.
> >
> > The output routines could then check the formats in the following order,
> > e.g. for "std::vector<char>":
> >
> > If there's a format set for std::vector<char>, use it, else
> > if there's a format set for std::vector<_> (all vectors), use it, else
> > use format for _.
> >
> > Comments?
>
> I like it :)

I found it quite neat, as well. :) Interestingly, one important contribution
of libraries are concepts and idioms. Since "_" is used as placeholder other
places, making it mean "any type" here is reasonably intuitive, as well.

> Using just _ scares me a bit... It would have to have a good default :)

Well, it doesn't matter that much, as all the formats are user-settable. The
library may provide a setting for _, but it can easily be set to something
else by the user, in the same way.

In fact, the current version in the Files (the first upload), has as
"defaults" that all strings are empty. So the defaults have existed from the
beginning, anyway. After all, you have to use _some_ format to print types
for which no explicit format has been set. Being able to set this default
explicitly, rather than hardcoding it in the library, should therefore be a
good thing.

In fact, I've made an implementation of the above, yesterday, and I'll just
make some more tests, and upload it to the Files section and Sandbox soon.
I'll post about it here when that's done.

Regards,

Terje


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