
Boost Users : 
From: David Abrahams (dave_at_[hidden])
Date: 20050531 14:24:21
"White Wolf" <wolof_at_[hidden]> writes:
> Hi Dave,
Hi Atilla,
In future please post your questions to the boostusers list so that
the whole community can benefit.
> I am trying to do something very simple, but I am going bananas. I have
> types, each of them has a "static member" (enum label) called nr_. I
> make a boost::mpl::list of them, and I would like to add them all
> together. But if I write _2::nr_, it says there is no nr_.
Well, the author of _2 can't anticipate all the nested values you
might be using. _2 is not magic; it's just a type.
// !! untested code !!
#include <boost/mpl/size_t.hpp>
#include <boost/mpl/plus.hpp>
using namespace mpl::placeholders;
// A metafunction to get an Element's ::nr_ value
template <class Element>
struct get_nr_
{
// all metadata are types, so wrap it in a type.
typedef mpl::size_t<Element::nr_> type;
};
typedef mpl::fold<
some_list, mpl::size_t<0>
, mpl::plus<
_1
, get_nr_<_2>
>
>::type sum;
// sum::value contains the value you're interested in.
> I fugured it wants a type. So I have made a typedef inside called
> type, which has a boost::mpl::integer_c<size_t, nr_> in it. But it
> does not work, it gives me back the type of the last list element as
> a result. I try to use mpl::accumulate.
Yes, that's a synonym for fold if you have a version of the MPL that
includes accumulate.
> Finally I guess I will have to use transform in some way, because I
> need a list which has an mpl::pair (if there is one)
http://www.boost.org/libs/mpl/doc/refmanual/pair.html
> of the original type and the sum of all nr_'s before it.
Seems like it's still a job for fold. In this case I'd use mpl::vector
because lists can only be push_fronted and you probably don't want to
end up with your elements in "reverse" order.
typedef mpl::fold<
some_list
, mpl::pair< // initial state
mpl::vector0 // initial sequence
, mpl::size_t<0> // initial sum
>
, mpl::pair< // the state at each step is a pair containing
mpl::push_front< // added to the front of...
mpl::first<_1> // the sequence from the previous step
, mpl::pair< // a new element, a pair containing
_2 // the original type
, mpl::plus< // and the sum of
mpl::second<_1> // the sum from previous step
, get_nr_<_2> // the ::nr_ of the original type
>
>
>
, mpl::plus< // and the sum of
mpl::second<_1> // the sum from previous step
, get_nr_<_2> // the ::nr_ of the original type
>
>
>::type pair_seq_sum;
typedef pair_seq_sum::first new_sequence;
So this is pretty verbose using lambdas because the sum is repeated,
among other things. You might do better to build a custom metafunction
that gets you the new state:
template <class PrevState, class Element>
struct next_state
{
typedef typename PrevState::first prev_sequence;
typedef typename PrevState::second prev_sum;
typedef mpl::size_t<(prev_sum::value + Element::nr_)> new_sum;
typedef typename mpl::push_back<
prev_sequence
, mpl::pair<Element, new_sum>
>::type new_sequence;
typedef mpl::pair<new_sequence, new_sum> type;
};
typedef mpl::fold< some_list, mpl::fold<_,_> >::type pair_seq_sum;
typedef pair_seq_sum::first new_sequence;
> Can you help me? I have
> something like this:
>
> struct T1 {
> enum x {
> label1,
> label2,
> nr_;
> };
> };
>
> // Same for T2, possibly less or more labels etc.
>
> And I would like to end up with a type which looks like this:
>
> struct something {
> int get(T1::x n) {
> return arr_[n];
> }
> int get(T2::x n) {
> return arr_[n+2];
Where does n+2 come from?
> }
> // etc.
> private:
> int arr_[sum_of_all_nr_];
> };
?? that doesn't look anything like what you just described.
Sheesh. The above is still a job for fold.
I suggest you start with a base type:
template <class Derived>
struct base
{
enum { sum = 0 };
void get(); // never used.
};
then build layers:
template <class Base, class T, class MostDerived>
struct layer : mpl::apply<Base, MostDerived>::type
{
typedef typename mpl::apply<Base, MostDerived>::type super;
enum { sum = T::nr_ + super::sum };
using Base::get;
int get(T::x n)
{
return static_cast<MostDerived*>(this)>arr_[n];
}
};
template <class Folded>
struct outer : Folded
{
int arr_[Folded::sum];
};
Well, the above "solution" won't work and I don't have time to write
something that does for you right now. It would take maybe another 15
minutes and I've already spent 30 on this email. I guess you'll
probably do best to make 2 passes over the sequence: one to compute
the sums and the other to build the result type. Good luck!
 Dave Abrahams Boost Consulting www.boostconsulting.com
Boostusers list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net