Boost logo

Boost :

From: Thorsten Ottosen (nesotto_at_[hidden])
Date: 2002-10-08 02:42:53


> ----- Original Message -----
> From: "Yitzhak Sapir" <yitzhaks <at> actimize.com>
>
> >
> > Why not make an iterator adaptor (initialization_iterator?) that holds a
> list of values with which to initialize. And then pass it to any of the
STL
> containers. (I can post my implementation if it's interesting):
> >
> > std::list<int> primes(
> > make_init_iterator<int>(2)(3)(5)(7)(11)(),
> > make_init_iterator<int>());
>
> I would like to see the code.

Included as an attachment.
[thor]
thanks.

> Anyway, what would the advanteges of this
> approach?

It seems to me to be more extensible and to integrate better with the
other Boost classes, in my opinion.
[thor]
not understood, really. Its a library for initializing primary the STL. I
have thought about
more boost classes like PropertyMap and the graph stuff: adjacency_list,
adjacency_matrix.
But it should be witha uniform syntax...and(excuse me for saying so) an
simple syntax ("as simple as possible but no ...") .

> Wouldn't it be slower because the the iterator adapter needs to
> store the values which
> are then copied? (I must admit, that speed was not really an initial
> concern, I focused on easy use). Another issue is the syntax, with the
stuff
> above, I don't
> thnk any newbie will use it very often.

Yes, it would be, but I think using a define to eliminate the heap
allocation and vector copy, you'd be left with just building up the vector
and a container copy. This leaves me with two traversals upon the
initializer list, as compared to your one traversal. But initialization
from a constant list is usually done once at the beginning of the
program/module/etc, and I doubt a factor of two at that point in the
program would be that detrimental. I really can't see how a good design
would put this sort of initialization inside an loop.

[thor]
at first speed wasn't an issue. but my test (see other mail) that there is
no overhead in my approach.
I don't think it is unthinkable that a loop could contain

set_cont( v ) += x,y,z;

which would otherwise have been

v.push_back( x );
v.push_back( y );
v.push_back( z );

but who knows. I agree that it's mostly for initialization, testing,
prototyping and learning situations.
-----

A more detailed answer:

Your interface is much more readable when used in practice. In the case
of maps, it has a pitfall that one could easily forget to properly place a
value in the list of initializer values (what about map<int, int>) and
then he'd be wondering where he messed up, because your interface can't
show him the place.
[thor]
not understood. Have you run a test? If you think about missing a single
value, the solution is easy. put a flag in the Map_comma_initializer
that is set false in operator,(); set the flag to true in
Map_data_initialiser
and the the destructor of Mapcomma_initializer test the flag. If you're
referrring
to a compile time error, then maybe the compile time list is better.
However,
its more complicated usage would be much worse than waiting for a runtime
initilization error.
--------

I dislike any name called "set_cont" because "set"
has so many meanings, besides being an STL class. I'd like initializer()
better. It may be longer but it conveys what is being done.
[thor]
when 'set' appears as a function name its always a verb in the imperative,
never a noun.
Thus you shouldn't be confused with the set class. In my vocabulary

set( v ) += ...

has only one meaning, and it conveys fine what's going one. Initializer is a
bad name because this is "fraud"

initialize( v ) = 1,2,3,4.

since ot will remove whatever v held before that statement. It's realy an
assignment.
, not initializing something.
-----

Also, I think you could make the interface easier by overloading your
adaptor function:
  template <class K, class D, class C, class A>
  Map_comma_initializer set_cont(std::map<K,D,C,A>& m);
(with similar uses for multimap/set/multiset) as opposed to the way you
have it now. This way you can have the same adaptor function for both
(and this is something that should be done for ease of use).

[thor]
good idea. What's the purpose of doing this for set, multiset? They already
work with
set_cont.
--------

And lastly, and most importantly, your interface seems to me to be not
extensible to user data types and even this seems like it wouldn't work:
typedef string street;
typedef int house_number;
typedef pair<street, house_number> address;
typedef string surname;
map<address, surname> addresses;
set_map(addresses) = "Washington St.", 30, "Johnson";

With my interface, the beginning user has to learn a bit, but he doesn't
have the pitfall of the map, and he can easily figure out how to
initialize an arbitrary data type (map<int, shared_ptr<Fruit> >) once he
understands the basic concepts.

[thor]
I don't agree. With your syntax above it's not clear what is the key and
what is data. Production code
would be

set_map(addresses) = address("Washington St.", 30), "Johnson";

which works fine already.
-----------------

I also think my interface integrates better with the Boost methodology.
For example, I think the same effect of your simpler enum_n_from can be
achieved using make_counting_iterator(). (The step-size portion cannot,
unfortunately, and I'd have liked counting iterator to have step size for
integer data types).

[thor]
who is to jugde what integrates better? A formal review board, I presume.
Ease of use was top priority. Any iterator stuff will probably ruin that.
I will wait for your step iterator too.
-----------

best regards

Thorsten


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