[mpl] erase_key confusion
I expect the following code to compile cleanly. It does not. #include <boost/mpl/set.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/erase_key.hpp> namespace mpl = boost::mpl; using mpl::_1; using mpl::_2; struct A {}; struct B {}; typedef mpl::set<A, B> set1; typedef mpl::set<B, A> set2; BOOST_MPL_ASSERT(( mpl::equal< mpl::erase_key<set1, A>::type, mpl::erase_key<set2, A>::type
)); I'm simply trying to assert that the sets {A,B} and {B,A} have the same elements after A has been removed from both. What am I doing wrong? Thanks, Scott
on Thu Mar 22 2007, Scott Meyers <usenet-AT-aristeia.com> wrote:
I expect the following code to compile cleanly. It does not.
#include <boost/mpl/set.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/erase_key.hpp>
namespace mpl = boost::mpl; using mpl::_1; using mpl::_2;
struct A {}; struct B {};
typedef mpl::set<A, B> set1; typedef mpl::set<B, A> set2;
BOOST_MPL_ASSERT(( mpl::equal< mpl::erase_key<set1, A>::type, mpl::erase_key<set2, A>::type
));
I'm simply trying to assert that the sets {A,B} and {B,A} have the same elements after A has been removed from both. What am I doing wrong?
Nothing; this is clearly a bug in MPL, better demonstrated by: #include <boost/mpl/set.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/erase_key.hpp> namespace mpl = boost::mpl; struct A {}; struct B {}; typedef mpl::set<A, B> ab_set; typedef mpl::erase_key<ab_set, A>::type b_set; BOOST_MPL_ASSERT(( boost::is_same< mpl::deref< mpl::begin<b_set>::type >::type , B >)); which yields: fu.cpp:17: error: No match for ‘assertion_failed( mpl_::failed ************ boost::is_same< boost::mpl::set2<A, B> , B>::************)’ In other words, erasing A from set<A,B> results in a sequence whose first element is set2<A,B>. I'll have to defer to Aleksey at this point, since he is the implementor. Aleksey? -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
Nothing; this is clearly a bug in MPL
As a workaround, I thought I'd write an erase_first function as shown below, but this seems to have the same problem. Perhaps this is because I'm using erase in my implementation, and erase_key may, I suppose, be implemented on top of erase. More likely, I'm doing something wrong. More likely still, the way I'm doing it is gross. I'd appreciate feedback on the implementation of my erase_first function, where I've put comments showing the procedural equivalent of what I'm trying to do in each statement. Also, does anybody have a workaround for the bug in erase_key? Thanks, Scott #include <boost/mpl/set.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/erase.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/end.hpp> #include <boost/mpl/find.hpp> namespace mpl = boost::mpl; using mpl::_1; using mpl::_2; struct A {}; struct B {}; typedef mpl::set<A, B> set1; typedef mpl::set<B, A> set2; // return Seq with the first occurrance of T removed template<typename Seq, typename T> struct erase_first { // i = Seq.find(T) typedef typename mpl::find<Seq, T>::type i; // found = (i == Seq.end()) ? false : true typedef typename mpl::if_< typename boost::is_same<i, typename mpl::end<Seq>::type >::type, mpl::false_, mpl::true_ >::type found; // type = found ? Seq : Seq.erase(i) typedef typename mpl::if_<found, Seq, typename mpl::erase<Seq, i>::type >::type type; }; BOOST_MPL_ASSERT(( mpl::equal< erase_first<set1, A>::type, erase_first<set2, A>::type
));
on Fri Mar 23 2007, Scott Meyers <usenet-AT-aristeia.com> wrote:
David Abrahams wrote:
Nothing; this is clearly a bug in MPL
As a workaround, I thought I'd write an erase_first function as shown below, but this seems to have the same problem. Perhaps this is because I'm using erase in my implementation, and erase_key may, I suppose, be implemented on top of erase.
It is *extremely* likely that erase_key and erase produce the same result.
More likely, I'm doing something wrong.
Not all that likely.
More likely still, the way I'm doing it is gross.
Well yeah. The un-gross way is to wait for Aleksey to fix it. He's unfortunately in a work crunch at the moment, but I'd guess he could address it within a couple of days.
I'd appreciate feedback on the implementation of my erase_first function, where I've put comments showing the procedural equivalent of what I'm trying to do in each statement.
Also, does anybody have a workaround for the bug in erase_key?
It's highly unlikely that any opportunity for such a workaround exists in the set code.
Thanks,
Scott
#include <boost/mpl/set.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/erase.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/end.hpp> #include <boost/mpl/find.hpp>
namespace mpl = boost::mpl; using mpl::_1; using mpl::_2;
struct A {}; struct B {};
typedef mpl::set<A, B> set1; typedef mpl::set<B, A> set2;
// return Seq with the first occurrance of T removed template<typename Seq, typename T> struct erase_first { // i = Seq.find(T) typedef typename mpl::find<Seq, T>::type i;
// found = (i == Seq.end()) ? false : true typedef typename mpl::if_< typename boost::is_same<i, typename mpl::end<Seq>::type >::type, mpl::false_, mpl::true_ >::type found;
mpl::if_< pred, mpl::false_, mpl::true_>::type is usually better written mpl::not_<pred>
// type = found ? Seq : Seq.erase(i) typedef typename mpl::if_<found, Seq, typename mpl::erase<Seq, i>::type >::type type; };
From scratch (untested):
template <class Seq, class E> struct erase_first { typedef typename mpl::find<Seq, T>::type i; typedef typename eval_if< boost::is_same<i, typename mpl::end<Seq> > , mpl::identity<Seq> , mpl::erase<Seq,i> >::type type; }; HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com
on Fri Mar 23 2007, David Abrahams <dave-AT-boost-consulting.com> wrote:
From scratch (untested):
And now, just by inspection...
template <class Seq, class E> struct erase_first { typedef typename mpl::find<Seq, T>::type i; typedef typename eval_if< boost::is_same<i, typename mpl::end<Seq> >
^::type
, mpl::identity<Seq> , mpl::erase<Seq,i> >::type type; };
HTH,
HTH-ly y'rs, -- Dave Abrahams Boost Consulting www.boost-consulting.com
On 3/23/07, Scott Meyers <usenet@aristeia.com> wrote:
// return Seq with the first occurrance of T removed template<typename Seq, typename T> struct erase_first { // i = Seq.find(T) typedef typename mpl::find<Seq, T>::type i;
// found = (i == Seq.end()) ? false : true typedef typename mpl::if_< typename boost::is_same<i, typename mpl::end<Seq>::type >::type, mpl::false_, mpl::true_ >::type found;
// type = found ? Seq : Seq.erase(i)
// type = found ? Seq.erase(i) : Seq
typedef typename mpl::if_<found, Seq, typename mpl::erase<Seq, i>::type >::type type;
typedef typename if_<found, typename mpl::erase<Seq, i>::type, Seq >::type type;
};
BOOST_MPL_ASSERT(( mpl::equal< erase_first<set1, A>::type, erase_first<set2, A>::type
));
Or did I misunderstand? Tony
Gottlob Frege wrote:
typedef typename if_<found, typename mpl::erase<Seq, i>::type, Seq >::type type;
Yes, thanks for this correction. Unfortunately, it doesn't change the behavior of the program. The assertion still fails when it should succeed. Any other suggestions? Thanks, Scott
On 3/23/07, Scott Meyers <usenet@aristeia.com> wrote:
Any other suggestions?
Thanks,
Scott
Do you know what the bug in mpl is? we have, essentially: : eval_if< has_key_impl<aux::set_tag>::apply<Set,T> , eval_if< is_same< T,typename Set::item_type_ > , base<Set> , identity< s_mask<T,Set> > > , identity<Set> > Can we assume kas_key_impl works? I would hope so, else mpl::set is a bit useless. The if (is_same) then base<Set> is pretty simple, so I suspect it is the s_mask<T, Set> that is causing problems. And, unfortunately, although staring for the usual requisite hour, s_mask, although small (or because it is small), makes no sense to me. In particular, I thought it would have a 'type' typedef'd somewhere in it, but I don't see it. Tony
on Fri Mar 23 2007, "Gottlob Frege" <gottlobfrege-AT-gmail.com> wrote:
And, unfortunately, although staring for the usual requisite hour, s_mask, although small (or because it is small), makes no sense to me.
In particular, I thought it would have a 'type' typedef'd somewhere in it, but I don't see it.
It inherits the ::type from its base class. -- Dave Abrahams Boost Consulting www.boost-consulting.com
Hi Scott, First of all, thanks for reporting this!
I expect the following code to compile cleanly. It does not.
#include <boost/mpl/set.hpp> #include <boost/mpl/equal.hpp> #include <boost/mpl/erase_key.hpp>
namespace mpl = boost::mpl; using mpl::_1; using mpl::_2;
struct A {}; struct B {};
typedef mpl::set<A, B> set1; typedef mpl::set<B, A> set2;
BOOST_MPL_ASSERT(( mpl::equal< mpl::erase_key<set1, A>::type, mpl::erase_key<set2, A>::type
));
I'm simply trying to assert that the sets {A,B} and {B,A} have the same elements after A has been removed from both. What am I doing wrong?
As David has already pointed out, your code is perfectly fine; it's a bug in the library. I'll look into fixing this within the next couple of days. Thanks for the report, -- Aleksey Gurtovoy MetaCommunications Engineering
Aleksey Gurtovoy writes:
As David has already pointed out, your code is perfectly fine; it's a bug in the library. I'll look into fixing this within the next couple of days.
Okay, this is fixed now (in the Boost CVS's HEAD), and the 'set' tests have been reworked to be more thorough. Once again, thanks for the report! -- Aleksey Gurtovoy MetaCommunications Engineering
participants (4)
-
Aleksey Gurtovoy
-
David Abrahams
-
Gottlob Frege
-
Scott Meyers