
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