|
Boost Users : |
From: David Abrahams (dave_at_[hidden])
Date: 2005-05-31 14:24:21
"White Wolf" <wolof_at_[hidden]> writes:
> Hi Dave,
Hi Atilla,
In future please post your questions to the boost-users 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_front-ed 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.boost-consulting.com
Boost-users 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