Boost logo

Boost Users :

From: Scott Meyers (usenet_at_[hidden])
Date: 2007-03-29 11:47:10


Joaquín Mª López Muñoz wrote:
> Hello Scott, I see several problems with your procedural approach: the first one
> is the ::type added to mpl::identity<Seq> and eraseVal<...> in the expression

Yes, I've mentioned in other threads that my understanding of when to use the
::type suffix is, um, incomplete at best. Thanks to postings by you and David
and others, the matter is slowly becoming somewhat clearer, I think.

> so that infinite recursion on eraseVal is avoided. But even after dropping those
> ::type's you still get errors like this:
>
> [...]/boost/mpl/next_prior.hpp: In instantiation of `boost::mpl::next<mpl_::void_>':

Yes, those errors look familiar, as does the existence of infinite recursion.
It turns out that infinite recursion tends to lead to lots of fairly unhelpful
error messages.

> The problem now is that, although the eraseVal<...> expression is only invoked
> (i.e. its nested ::type calculated) when strictly necessary --this is what eval_if
> is
> used for--, its first argument is computed *always*, regardless of what branch
> of the eval_if<...> expr is finally selected:

Is this sort of like saying that although a metafunction may not be invoked,
it's arguments are always calculated? I'm probably still stuck in the
procedural world, but my expectation was that the false branch would not be
"taken" when the condition was false, but it's still murky to me what it means
to "take" a branch, because where "taking" it entails some kind of template
expansion along it. At least that's what I currently think.

> expression (Incidentally, a ::type is missing for mpl::erase<...>

Sigh.

> So, what we need if to add a layer of indirection so as to not invoke the
> arguments to the recursive call to eraseVal except when strictly necessary,
> like for instance as follows:
>
> template<typename Seq,typename T>
> struct eraseVal
> {
> template<typename Iter>
> struct eraseValRecurse:
> eraseVal<typename mpl::erase<Seq,Iter>::type,T>
> {};
>
> typedef typename mpl::find<Seq,T>::type iter;
>
> typedef typename mpl::eval_if<
> boost::is_same<iter,typename mpl::end<Seq>::type>,
> mpl::identity<Seq>,
> eraseValRecurse<iter>

And this works because we evaluate only iter in this last statement, not
eraseValRecurse<iter> -- is that correct?

> template<typename Seq,typename T>
> struct eraseVal2:mpl::copy_if<Seq,mpl::not_<boost::is_same<mpl::_,T> > >
> {};

YOU ARE A GOD! Thank you very much! What's really embarrassing now that I see
this is that it's morally akin to code I show in Effective STL for essentially
the same operation on associative containers. There is a tiny chance I would
have thought of this had I noticed the existence of copy_if in the MPL, so part
of the moral of the story is that I need to familiarize myself better with the
extent of the functionality in the MPL.

Thank you so much, I really appreciate it. With help from you and the others on
this list, I anticipate my MPL productivity skyrocketing to upwards of one line
per day. Counting comments, of course :-)

Scott


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