mpl -> integral sequence wrappers -> wrapping enums ?
Hello MPL experts, I'd like to use meta - vectors of integral constants defined as enums. But unfortunately the code below does not compile. <code> #include <iostream> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/size.hpp> enum MY_ENUM {X,Y}; // (*) typedef boost::mpl::vector_c<MY_ENUM,X,Y> my_vector_c; static const int size = boost::mpl::size<my_vector_c>::value; int main(int argc, char** argv) { std::cout << "\nsize:" << size << "\n... bye" << std::endl; } </code> After replacing line (*) with typedef boost::mpl::vector_c<int,X,Y> my_vector_c; the code compiles and runs fine, but this does not look type safe any more. Any suggestions ?! regards, Martin.
Hello MPL experts ! Stepping forward in dealing with a mpl::vector_c of enums I found it hard to determine the correct expression to 'mpl::find' an element within such a vector. The code below compiles with gcc 3.3.3 and shows 5 different approaches, but only version 4,5 really find the correct iterator. Version 1,2,3 return iterators pointing to the vectors end. It would be helpful if someone more familiar with MPL's concepts could give some explanation, particularly about the aspects: - Is there a solution using mpl::find instead of mpl::find_if If not, why the difference between finding elements in mpl::vector and mpl::vector_c ? - What is the difference between using integral wrappers: boost::mpl::integral_c<MY_ENUM,c> > boost::mpl::int_<c> - And still the question from the previous posting: Can I (should I) tell mpl::vector_c I'm using my own enum type and not plain int ? regards, Martin. <CODE> #include <iostream> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/find.hpp> #include <boost/mpl/find_if.hpp> #include <boost/mpl/end.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/integral_c.hpp> #include <boost/mpl/comparison.hpp> #include <boost/mpl/distance.hpp> #include <boost/mpl/placeholders.hpp> using namespace boost::mpl::placeholders; enum MY_ENUM {X=12,Y=24,Z=36}; typedef boost::mpl::vector_c<int,X,Y> my_vector_c; template<typename MyEnums,MY_ENUM c> struct test { static const MY_ENUM value = c; typedef typename boost::mpl::find<MyEnums,boost::mpl::int_<c> >::type c_iter_1; typedef typename boost::mpl::find<MyEnums,boost::mpl::integral_c<MY_ENUM,c> >::type c_iter_2; typedef typename boost::mpl::find<MyEnums,boost::mpl::integral_c<MY_ENUM,c> >::type c_iter_3; typedef typename boost::mpl::find_if<MyEnums,boost::mpl::equal_to<_1,boost::mpl::int_<c> > >::type c_iter_4; typedef typename boost::mpl::find_if<MyEnums,boost::mpl::equal_to<_1,boost::mpl::integral_c<MY_ENUM,c> > >::type c_iter_5; // these 3 lines are only for showing the end iterators position: typedef typename boost::mpl::end<MyEnums>::type end_iter; typedef typename end_iter::pos end_pos_t; static const int end_pos = end_pos_t::value; }; int main(int argc, char** argv) { std::cout << "\ntest<.,X>::end_pos:" << test<my_vector_c,X>::end_pos << std::endl; std::cout << "\ntest<.,Y>::c_iter_1::pos::value:" << test<my_vector_c,Y>::c_iter_1::pos::value << std::endl; std::cout << "\ntest<.,Y>::c_iter_2::pos::value:" << test<my_vector_c,Y>::c_iter_2::pos::value << std::endl; std::cout << "\ntest<.,Y>::c_iter_3::pos::value:" << test<my_vector_c,Y>::c_iter_3::pos::value << std::endl; std::cout << "\ntest<.,Y>::c_iter_4::pos::value:" << test<my_vector_c,Y>::c_iter_4::pos::value << std::endl; std::cout << "\ntest<.,Y>::c_iter_5::pos::value:" << test<my_vector_c,Y>::c_iter_5::pos::value << std::endl; } </CODE>
Martin Pasdzierny writes:
Stepping forward in dealing with a mpl::vector_c of enums I found it hard to determine the correct expression to 'mpl::find' an element within such a vector. The code below compiles with gcc 3.3.3 and shows 5 different approaches, but only version 4,5 really find the correct iterator. Version 1,2,3 return iterators pointing to the vectors end. It would be helpful if someone more familiar with MPL's concepts could give some explanation, particularly about the aspects:
- Is there a solution using mpl::find instead of mpl::find_if
Yes (assuming that the sequence you are searching in satisfies Integral Sequence Wrapper requirements): typedef vector_c<int,X,Y> v; typedef find< v, integral_c<int,c> >::type iter; ^^^
If not, why the difference between finding elements in mpl::vector and mpl::vector_c ?
'find' uses *type equality* ('boost::is_same') to determine whether the elements are the same, and from standpoint of the C++ compiler, all these integral_c<MY_ENUM,c> integral_c<int,c> int_<c> have different types, so you have to be precise in specifying what exactly you are looking for. The 'find' snippet above is guaranteed to work because all Integral Sequence Wrappers classes are required to be wrappers around seqn<integral_c<T,c1>,integral_c<T,c2>, ... integral_c<T,cn> > (see http://www.boost.org/libs/mpl/doc/refmanual/integral-sequence-wrapper.html). Note that unless you have control over how your sequences of integral constants are constructed, the approach is fragile: typedef vector_c<int,X,Y> v1; typedef find< v1, integral_c<int,X> >::type iter1; // OK typedef push_back< my_vector_c, int_<Z> >::type v2; // ^^^^^^^ typedef find< v1, integral_c<int,Z> >::type iter2; // Nothing found! The current recommendation for generic code working with integral constants is to always use explicit 'equal_to' comparison. If you find this too verbose, you might consider writing a helper metafunction that would wrap this up for you, e.g.: template< typename Seq, typename Seq::value_type N > struct find_c : find_if< Seq, equal_to<_1, integral_c<typename Seq::value_type,N> > { }; typedef find_c< v1, Z >::type iter2; // Works
- What is the difference between using integral wrappers: boost::mpl::integral_c<MY_ENUM,c> > boost::mpl::int_<c>
See the above.
- And still the question from the previous posting: Can I (should I) tell mpl::vector_c I'm using my own enum type and not plain int ?
Not at the moment, see my earlier reply. HTH, -- Aleksey Gurtovoy MetaCommunications Engineering
Martin Pasdzierny writes:
I'd like to use meta - vectors of integral constants defined as enums. But unfortunately the code below does not compile.
<code> #include <iostream> #include <boost/mpl/vector_c.hpp> #include <boost/mpl/size.hpp>
enum MY_ENUM {X,Y}; // (*) typedef boost::mpl::vector_c<MY_ENUM,X,Y> my_vector_c; static const int size = boost::mpl::size<my_vector_c>::value;
int main(int argc, char** argv) { std::cout << "\nsize:" << size << "\n... bye" << std::endl; } </code>
After replacing line (*) with
typedef boost::mpl::vector_c<int,X,Y> my_vector_c;
the code compiles and runs fine, but this does not look type safe any more.
Any suggestions ?!
Martin, There is not much you can do on a user side to make it work, but we'll look into fixing this for the next release. Meanwhile, I'd suggest to go with 'vector_c<int,X,Y>' version you cite above. -- Aleksey Gurtovoy MetaCommunications Engineering
participants (2)
-
Aleksey Gurtovoy
-
Martin Pasdzierny