MPL::lambda issue: what am I doing wrong?

I want to express a "type-mapping" scheme. My implementation idea is this: have the user define an MPL sequence comprised exclusively of std::pair derivations. He can then instantiate my template class with his sequence as the argument. My template then derives two MPL sequences, one containing the "first" types, the other containing the "second" types. Here is the attempt: <code> namespace ls { using namespace boost::mpl; using namespace placeholders; template <class TypePairSequence> struct list_splitter { template <class STDPAIR> struct first_type { typedef typename STDPAIR::first_type type; }; template <class STDPAIR> struct second_type { typedef typename STDPAIR::second_type type; }; typedef typename transform < TypePairSequence , first_type<_1> > ::type first_types; typedef typename transform < TypePairSequence , second_type<_1> >::type second_types; }; }//end namespace ls </code> Here is an attempt to instantiate: 1> typedef boost::mpl::list< std::pair<long, short>, std::pair<char, double>
associated_types; 2> typedef ls::list_splitter<associated_types> split_associated_types; 3> typedef split_associated_types::first_types first_types; 4> typedef split_associated_types::second_types second_types; 5> typedef boost::mpl::at_c<first_types, 0>::type first_first_t; Code lines 1-2 compile fine. When I add line 3, I get the following error: "no type named `first_type' in `struct boost::mpl::arg<1>'". If you need more: <error> temp.h: In instantiation of `ls::list_splitter<associated_types>::first_type<boost::mpl::arg<1> >': boost/mpl/transform.hpp:41: instantiated from `boost::mpl::apply1<ls::list_splitter<associated_types>::first_type<boost::m pl::arg<1> >, std::pair<char, double> >' boost/mpl/transform.hpp:41: instantiated from `boost::mpl::aux::transform_op<ls::list_splitter<associated_types>::first_ty pe<boost::mpl::arg<1> > >::apply<boost::mpl::null_node, std::pair<char, double> >' boost/mpl/aux_/preprocessed/gcc/fold_backward_impl.hpp:74: instantiated from `boost::mpl::aux::fold_backward_impl<2, boost::mpl::list_iterator<boost::mpl::list2<std::pair<long int, short int>, std::pair<char, double> > >, boost::mpl::list_iterator<boost::mpl::null_node>, boost::mpl::null_node, boost::mpl::protect<boost::mpl::aux::transform_op<ls::list_splitter<associat ed_types>::first_type<boost::mpl::arg<1> > > >, boost::mpl::arg<1> >' boost/mpl/fold_backward.hpp:45: instantiated from `boost::mpl::fold_backward<associated_types, boost::mpl::null_node, boost::mpl::protect<boost::mpl::aux::transform_op<ls::list_splitter<associat ed_types>::first_type<boost::mpl::arg<1> > > >, boost::mpl::arg<1> >' boost/mpl/transform.hpp:64: instantiated from `boost::mpl::algo_::transform<associated_types, ls::list_splitter<associated_types>::first_type<boost::mpl::arg<1> > >' temp.h:35: instantiated from `ls::list_splitter<associated_types>' temp.h:53: instantiated from here temp.h:19: no type named `first_type' in `struct boost::mpl::arg<1>' </error>
I'm sure I'm overlooking something simple. Could someone point me in the right direction? I'm using gcc3.2.2 on Solaris 9. TIA, Brian

Brian Simpson wrote:
I want to express a "type-mapping" scheme. My implementation idea is this: have the user define an MPL sequence comprised exclusively of std::pair derivations. He can then instantiate my template class with his sequence as the argument. My template then derives two MPL sequences, one containing the "first" types, the other containing the "second" types. Here is the attempt: <code> namespace ls { using namespace boost::mpl; using namespace placeholders;
template <class TypePairSequence> struct list_splitter { template <class STDPAIR> struct first_type { typedef typename STDPAIR::first_type type; }; template <class STDPAIR> struct second_type { typedef typename STDPAIR::second_type type; };
typedef typename transform < TypePairSequence , first_type<_1> > ::type first_types;
typedef typename transform < TypePairSequence , second_type<_1> >::type second_types; };
}//end namespace ls </code>
Here is an attempt to instantiate: 1> typedef boost::mpl::list< std::pair<long, short>, std::pair<char, double>
associated_types; 2> typedef ls::list_splitter<associated_types> split_associated_types; 3> typedef split_associated_types::first_types first_types; 4> typedef split_associated_types::second_types second_types; 5> typedef boost::mpl::at_c<first_types, 0>::type first_first_t; Code lines 1-2 compile fine. When I add line 3, I get the following error: "no type named `first_type' in `struct boost::mpl::arg<1>'".
[...]
I'm sure I'm overlooking something simple. Could someone point me in the right direction? I'm using gcc3.2.2 on Solaris 9.
Brian, I don't have access to gcc 3.2.2 at the moment, but it looks like they are still not able to handle the class template arity issues correctly (your example also fails with an internal compiler error on 3.2). The essence of the issue is that gcc adopts a non-standard extension under which two class template specializations like these template< typename T > struct lambda { typedef T type; }; template< template< typename > class F , typename T1 > struct lambda< F<T1> > { }; template< template< typename, typename > class F , typename T1, typename T2 > struct lambda< F<T1,T2> > { }; cause an ambiguity when instantiated on another class template with one or more default template parameters: template< typename T1, typename T2 = void > struct my {}; lambda< my<int> > l; // error here Basically, the extension is non-conforming and IMO is a bug, but for some reason gcc developers have been reluctant to admit so ;). Anyway, to make the long story short, MPL tries to deal with the ambiguity above by using a sophisticated method for determining the "true" template arity even under these unfriendly conditions - but due to other compiler bugs it still didn't always work properly in 3.2. Seems like in 3.2.2. things didn't change for the better. The good news is that if you re-write your metaprogram as follows, it will work: #include "boost/mpl/list.hpp" #include "boost/mpl/lambda.hpp" #include "boost/mpl/transform.hpp" #include "boost/mpl/select1st.hpp" #include "boost/mpl/select2nd.hpp" #include "boost/mpl/pair.hpp" namespace ls { using namespace boost::mpl; using namespace placeholders; template <class TypePairSequence> struct list_splitter { typedef typename transform < TypePairSequence , boost::mpl::select1st<_1> > ::type first_types; typedef typename transform < TypePairSequence , boost::mpl::select2nd<_1> >::type second_types; }; }//end namespace ls typedef boost::mpl::list< boost::mpl::pair<long, short>, boost::mpl::pair<char, double> > associated_types; typedef ls::list_splitter<associated_types> split_associated_types; typedef split_associated_types::first_types first_types; If you want to know more details, just ask :). HTH, Aleksey

"Aleksey Gurtovoy" <alexy@meta-comm.com> wrote:
Brian Simpson wrote:
I want to express a "type-mapping" scheme. My implementation idea is this: have the user define an MPL sequence comprised exclusively of std::pair derivations. He can then instantiate my template class with his sequence as the argument. My template then derives two MPL sequences, one containing the "first" types, the other containing the "second" types.
[...]
I'm using gcc3.2.2 on Solaris 9.
Brian, I don't have access to gcc 3.2.2 at the moment, but it looks like they are still not able to handle the class template arity issues correctly (your example also fails with an internal compiler error on 3.2). [...] The good news is that if you re-write your metaprogram as follows, it will work: [...]
If you want to know more details, just ask :).
HTH, Aleksey
That does help. It gets me to the next (apparent) obstacle, which is that I need to define a variant using the types in the derived sequence (the second_types, to be specific). I'm putting together another post for that one. BTW, would it be possible, using mpl::fold, to get Borland5 to do this? I know that it won't support mpl::lambda, and I'd like my code to compile on Borland5 in addition to gcc3.2.2 . I'll be looking into it, but if you can alert me that it's not possible, that would save me time :). I'm sure I'll be asking for more details later, but for now the documentation is coming through for me. Thanks! Brian

Brian Simpson wrote:
It gets me to the next (apparent) obstacle, which is that I need to define a variant using the types in the derived sequence (the second_types, to be specific).
Are we talking about 'boost::variant' here? Because the latter accepts MPL-sequence template arguments directly - you just pass a sequence to it, and that's all.
I'm putting together another post for that one.
BTW, would it be possible, using mpl::fold, to get Borland5 to do this? I know that it won't support mpl::lambda, and I'd like my code to compile on Borland5 in addition to gcc3.2.2 . I'll be looking into it, but if you can alert me that it's not possible, that would save me time :).
All MPL algorithms that take lambda expressions can also take _metafunction classes_, so if lambda is unavailable/too complicated, you can always write a standalone auxiliary metafunction class that does what you want and just pass it to the algorithm, e.g. struct do_something { template< typename State, typename T > struct apply { // ... typedef ... type; }; }; // ... typedef mpl::fold< seq, do_something >::type result; Just like you would do it in STL without Boost.Lambda :).
I'm sure I'll be asking for more details later, but for now the documentation is coming through for me.
Good! Aleksey

"Aleksey Gurtovoy" <alexy@meta-comm.com> wrote in message news:00f701c347cf$e0252940$d2f2d90c@metacomm.com...
Brian Simpson wrote:
It gets me to the next (apparent) obstacle, which is that I need to define a variant using the types in the derived sequence (the second_types, to be specific).
Are we talking about 'boost::variant' here? Because the latter accepts MPL-sequence template arguments directly - you just pass a sequence to it, and that's all.
[...] Oops. I got the impression, from the conversations resulting from the review of boost::variant, that that feature was being removed. I'll try it and see what I get. Meanwhile, just before I got your post, I submitted another one, which deals with this same problem applied to boost::tuple. I'll do a little research over the weekend to see if I jumped the gun there, too ;) . --Brian
participants (2)
-
Aleksey Gurtovoy
-
Brian Simpson