|
Boost : |
From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2003-11-16 05:44:16
Arkadiy Vertleyb wrote:
> Hi Aleksey,
Hi Arkadiy,
> > If you have to care about broken compilers, I
> > would recommend you to use 'bind' and 'select1st's metafunction-class
form
> > instead:
> >
> > typedef apply2<
> > bind1<select1st<>,_2>
> > , char
> > , pair<int,bool>
> > >::type res;
> >
> > BOOST_MPL_ASSERT_IS_SAME(res,int);
> >
> > This one is guaranteed to work for all library templates.
>
> It turnes out that this workaround doesn't work with gcc 3.3.
It won't work on any conforming compiler, since the code is incorrect -
please see below.
> The following
> code doesn't compile:
>
> typedef mpl::vector4<
> mpl::pair<int, int*>,
> mpl::pair<short, short*>,
> mpl::pair<long, long*>,
> mpl::pair<char, char*>
> > pairs;
>
> typedef mpl::find_if<
> pairs,
> boost::is_same<mpl::bind1<mpl::select1st<>, mpl::_>, long> >::type
iter;
Uhmm, this one doesn't work because 'mpl::bind1<mpl::select1st<>, mpl::_>'
(and therefore the whole predicate) is not a lambda expression; a result of
any 'bind' template instantiation is a plain metafunction class. IOW, the
above is pretty much equivalent to
typedef mpl::find_if<
pairs,
boost::is_same<is_first_same_as_long, long> >::type iter;
for which it's obvious (I hope) that it won't work as intended.
If an analogy will help, a run-time equivalent of the above would be writing
std::find_if(s.begin(), s.end()
, std::equal_to<...>(boost::bind(....), long)
);
instead of
std::find_if(s.begin(), s.end()
, boost::bind(std::equal_to<...>()
, boost::bind(....)
, long
)
);
Obviously, one way to fix our problem would be to do the same thing as in
the run-time code - wrap the whole predicate into another 'bind'
instantiation:
typedef mpl::find_if<
pairs
, mpl::bind2<
mpl::quote2<boost::is_same>
, mpl::bind1<mpl::select1st<>, mpl::_>
, long
>
>::type iter;
... with the only caveat that 'mpl::quote2' requires template template
parameters support. To fix that, we can further rewrite the expression as
// 'same_as' was introduced specifically for the cases like this one
typedef mpl::find_if<
pairs
, mpl::bind1<
mpl::same_as<long>
, mpl::bind1<mpl::select1st<>, mpl::_>
>
>::type iter;
... but the one I would actually recommend you to use would be this:
typedef mpl::find<
mpl::transform_view< pairs,mpl::select1st<> >
, long
>::type::base iter;
Please see http://tinyurl.com/v76f for 'transform_view' details.
HTH,
Aleksey
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk