Re: Metaprogramming woes
"White Wolf" <wolof@freemail.hu> 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
David Abrahams <dave@boost-consulting.com> writes:
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;
Heh, this probably would've been easier using zip_view. Oh, well, I'm outta time for this one right now. Again, sorry. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (1)
-
David Abrahams