Boost logo

Boost :

From: Arkadiy Vertleyb (vertleyb_at_[hidden])
Date: 2003-11-28 18:43:09


Hi David,

Thanks for your reply and for the link to the archive.

>>select1st is defined with default arguments, and then specialized so
>>that when the defaults are used you have a metafunction class:
>>
>> template <class P = _>
>> struct select1st
>> {
>> typedef ... type; // whatever
>> };
>>
>> template <>
>> struct select1st<_>
>> {
>> template <class P>
>> struct apply : select1st<P>
>> {};
>> };

OK, now I understand.

>>> And can we apply the same form of select1st in other contexts?
>>
>>Yes.
>>
>>> What do we do if anything needs to be passed to select1st?
>>
>>Use mpl::apply.

Actualy I meant using select1st in lambda expressions that are passed to
algorithms... From your explanation, select1st<> with no parameters is a
metafunction class that gets the "first" typedef from the type passed. But
what if we have to use it in a combination with something else, say in
iter_fold. We don't have the type there -- we have an iterator. So, in
this case we can't use select1st<> with default parameter -- we have to
supply the parameter, something like:

select1st<deref<_1> >

And this again will complain about lack of "first" typedef in deref (in
VC6.5)

>>> Meanwhile I was going to use a simple workaround that seams to work with
>>> find_if, transform_view, etc. (I tried it with VC6 and GCC 3.3):
>>>
>>> template<class T>
>>> struct fake1st : T
>>> {
>>> typedef int first;
>>> typedef T type;
>>> };
>>>
>>> main()
>>> {
>>> typedef mpl::vector<
>>> mpl::pair<char, char*>,
>>> mpl::pair<long, long*>,
>>> mpl::pair<int, int*>
>>> > pairs;
>>>
>>> // works with transform_view, too
>>>
>>> typedef mpl::find_if<
>>> pairs,
>>> boost::is_same<mpl::select1st<fake1st<mpl::_1> >, int>
>>> >::type it;
>>>
>>> typedef mpl::select2nd<mpl::deref<it>::type>::type type;
>>> BOOST_MPL_ASSERT_IS_SAME(type, int*);
>>>
>>> return 0;
>>> }
>>>
>>> If I understand things correctly, this should work with both approaches:
>>>
>>> 1. On a deficient compiler, fake1st<_1>::apply<...> means
_1::apply<...>,
>>> since it is inherited;
>>
>> _1::apply<X>::type
>>
>>is just
>>
>> X
>>
>>So I don't think this does what you want. But then fake1st is also
>>just the identity metafunction, so if that's all you want why not
>>just use mpl::identity?

Actually it's not just identity -- it adds "first" typedef. This is the
purpose of it -- add the typedef to satisfy VC6 without changing anything
else...

>>> 2. On a conforming compiler fake1st will be (like any template)
>>> lambda-enabled, so
>>>
>>> apply<fake1st<_1>, ...>::type
>>>
>>> should boil down to
>>>
>>> fake1st<apply<_1, ...>::type>::type
>>>
>>> which is (due to the second typedef in fake1st):
>>>
>>> apply<_1, ...>::type
>>>
>>> What do you think about this?
>>
>>Why jump through hoops?

I will not use my workaround unless the authors of MPL approve it. I
wouldn't like to hack MPL, and my understanding of the subject is far from
perfect. But then, how do I workaround the problem in a PORTABLE way,
preferably with no #ifdefs? And, if the #ifdef is necessary, which
configuration constant should be used?

Thanks for your help,

Arkadiy

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
_______________________________________________
Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost
From: David Abrahams <dave <at> boost-consulting.com>Subject: Re: MPL/lambda
questionNewsgroups: gmane.comp.lib.boost.develDate: Wed, 19 Nov 2003
07:25:45 +0000"Arkadiy Vertleyb" <vertleyb <at> hotmail.com> writes:
> Hi Aleksey,
>
>> > 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.
>
> It is KIND OF obvious...  If I understand bind correctly, it should
decrease
> the arity of a functor.  So, since select1st is a unary functor (taking a
> pair), then bind1<mpl::select1st<>, _> has to be a nullary one...
Nope, it's the same as writing boost::bind(select1st, _1): that is,
it just creates a "function object" (a metafunction class in the
compile-time world).
>> ... 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;
>
> Now I am totaly confused....  how does THIS work?
select1st is defined with default arguments, and then specialized so
that when the defaults are used you have a metafunction class:
     template <class P = _>
     struct select1st
     {
        typedef ... type; // whatever
     };
     template <>
     struct select1st<_>
     {
        template <class P>
        struct apply : select1st<P>
        {};
     };
> And can we apply the same form of select1st in other contexts?
Yes.
> What do we do if anything needs to be passed to select1st?
Use mpl::apply.
> Meanwhile I was going to use a simple workaround that seams to work with
> find_if, transform_view, etc. (I tried it with VC6 and GCC 3.3):
>
> template<class T>
>     struct fake1st : T
> {
>     typedef int first;
>     typedef T type;
> };
>
> main()
> {
>     typedef mpl::vector<
>         mpl::pair<char, char*>,
>         mpl::pair<long, long*>,
>         mpl::pair<int, int*>
>         > pairs;
>
>     // works with transform_view, too
>
>     typedef mpl::find_if<
>         pairs,
>         boost::is_same<mpl::select1st<fake1st<mpl::_1> >, int>
>         >::type it;
>
>     typedef mpl::select2nd<mpl::deref<it>::type>::type type;
>     BOOST_MPL_ASSERT_IS_SAME(type, int*);
>
>     return 0;
> }
>
> If I understand things correctly, this should work with both approaches:
>
> 1.  On a deficient compiler, fake1st<_1>::apply<...> means _1::apply<...>,
> since it is inherited;
  _1::apply<X>::type
is just
   X
So I don't think this does what you want.  But then fake1st is also
just the identity metafunction, so if that's all you want why not
just use mpl::identity?
> 2.  On a conforming compiler fake1st will be (like any template)
> lambda-enabled, so
>
>     apply<fake1st<_1>, ...>::type
>
> should boil down to
>
>     fake1st<apply<_1, ...>::type>::type
>
> which is (due to the second typedef in fake1st):
>
>     apply<_1, ...>::type
>
> What do you think about this?
Why jump through hoops?
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
_______________________________________________
Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk