Boost logo

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