Boost logo

Boost :

From: Larry Evans (cppljevans_at_[hidden])
Date: 2005-04-26 15:38:05


On 04/26/2005 10:30 AM, Giovanni Piero Deretta wrote:
> On 4/26/05, Larry Evans <cppljevans_at_[hidden]> wrote:
>
[snip]
> Anyway, the get<type> form is most useful with tuples containing
> elements of different type. In practice you overload the meaning of
> the type to also be a an element tag. This way tuples become as

But isn't an enumerator in some enumeration the equivalent of
an "element tag"?

> powerful as structures: you can access element by "name". They are

The enumerator can also be thought of as a name.

> more powerful actually, as they have introspection capability:
> elements can be enumerated. Also the possibility of accessing tuple
> elements indipendently of the exact tuple type and element position
> can be very handy in generic programming.

Which can be done with enumerators also.

>
> The get<type> form that i proposed can be easily added with zero
> changes to the existing tuple code/interface.
> A more complex addition would allow the association of a tag to each
> tuple element i.e.:
> tuple<mpl::list<element1_type, element1_tag>, mpl::list<element2_type,
> element2_tag>,.....>
> a get<elementn_tag> would return the nth element. This would make the
> tag unique and maybe open new possibilities.

But again, I don't see why adding a tag is any better than using an
enumerator. The only difference between an array (all elements of
the same type) and a tuple, is that the type of the value as well
as the value depends on the index. And if the types are indexed
by the same enumeration, then you've solve the problem. In addition,
a similar scheme can be used for variants (or disjoint sum). See

http://cvs.sourceforge.net/viewcvs.py/boost-sandbox/boost-sandbox/libs/indexed_types/test/sum.cpp?view=markup

>
> BTW, tuples containing many objects of the same type are better seen
> as containers, thus the indexed get is fine.

Agreed, but the indexed get works just as well when the argument is
an enumerator instead of a literal unsigned, and when it's an
enumerator, the meaning is clearer:

     t.get<0>();
     t.get<1>();

is obviously not as clear as:

     t.get<first_field>();
     t.get<second_field>();

[snip]
> In a theoretical extended_tuple, the enum could be part of the tuple
> itself, so you could do 'get<my_tuple.element1> (my_tuple)' and there
> would not be no name conflict. The problem with enums is that you
> have to maintain them separately: this is information duplication that
> could easily go out of sync.

Not if you use either something like mpl's map:
<-------------------- cut here ---------------------
   struct
enum_map_0
{
       enum
     field_names
     { f_0
     , f_1
     , f_2
     };

       template<field_names FieldName>
       struct
     field_name
     {};

         typedef
       mpl::map
       < mpl::pair<field_name<f_0>, type_i<0> >
       , mpl::pair<field_name<f_1>, type_i<0> >
       , mpl::pair<field_name<f_2>, type_i<1> >
>
     field_map
     ;
};

void test(void)
{
     mpl::tuple_enum<enum_map_0> tuple_0;
     type_i<0>& f0=tuple_0.get<enum_map_0::f_0>();
}

>-------------------- cut here ---------------------
or use a specialization of a template indexed by the
enumeration, as shown in the boost-sandbox sum.cpp
file mentioned above or in another test file, product.cpp,
in the same location.

I'm not sure which is better.


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