Re: [Boost-users] [boost.mpl] Implementing a numeric index access to fields of a composite class created with mpl::inherit_linearly

Hello,
I created the following composite class using mpl::inherit_linearly:
template <class T> struct DataField { T data; }
typedef mpl::inherit_linearly< mpl::vector< int, int, int> mpl::inherit< DataField<_2>, _1 >
Int3Composite;
Int3Composite int3comp;
Since the type of each data field is an int, I cannot use the type of the field to access the data in the field.
Q: Is there a way to write a template (call it get_field) to access the data using numeric
Hi! you could use an mpl::pair type to produce a static mapping of int value to type: mpl::pair<mpl::int_<0>, int> This is a little bit ugly, to write such a big construct, so you can write the following construct template<int N, class T> struct pair_c : mpl::pair<mpl::int_<N>, T> {}; Actually pair_c could be your DataField struct, so you can add the T instance to it: template<int N, class T> struct pair_c : mpl::pair<mpl::int_<N>, T> { T dataField; }; Now you can define a vector of pair types as follows: mpl::vector<pair_c<0, int>, pair_c<1, int>, pair_c<2, int> > my_vector; we use in this sample pair_c to make any type unique, dependent on the position in the vector. The next step would be to define the class with linear inheritance: template<class Seq> struct linear_inherited : boost::mpl::inherit_linearly < Seq , boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2> >::type {}; But now you would need the access function. I suggest to integrate this function as a linear_inherited member: template<class Seq> struct linear_inherited : boost::mpl::inherit_linearly < Seq , boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2> >::type { template<long N> typename boost::mpl::at_c<Seq, N>::type::second& nth_field() { typedef typename boost::mpl::at_c<Seq, N>::type* ptr_type; ptr_type ptr = static_cast<ptr_type>(this); return ptr->dataField; } }; When this function is a member you save some effor on passing the sequence type to its specialization, otherwise it will not know which type is meant. Let me explain this function: mpl has the at metafunction, which can access the Nth element of a static vector. Here this function is used to calculate the result_type (in our case it is always int, but we want to be generic ;), so you can make pair_c<0, double>, pair_c<1, SomeStruct> etc.). The at metafunction returns the type which was in the vector at this position, in our case this type is pair_c. Now we need to access the field type T. mpl::pair is defined as template <class X, class Y> struct pair { typedef X first; typedef Y second; }; so, the type of our datafield in pair_c is of type second. Therefore the function nth_field returns reference to second. In the function itself we use the static_cast operator to calculate the offset to our datafield within the class. And then we return the the field contained there. Below is the full listing I used to test and compile the scenario: linear_inh_test.h ---------- START ------------------- #ifndef __OM_LINEAR_INHERITANCE_TEST_H__ #define __OM_LINEAR_INHERITANCE_TEST_H__ #include <boost/mpl/at.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/pair.hpp> #include <boost/mpl/lambda.hpp> #include <boost/mpl/inherit.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/inherit_linearly.hpp> template<int N, class T> struct pair_c : boost::mpl::pair<boost::mpl::int_<N>, T> { T dataField; }; template<class Seq> struct linear_inherited : boost::mpl::inherit_linearly < Seq , boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2> >::type { template<long N> typename boost::mpl::at_c<Seq, N>::type::second& nth_field() { typedef typename boost::mpl::at_c<Seq, N>::type* ptr_type; ptr_type ptr = static_cast<ptr_type>(this); return ptr->dataField; } }; #endif __________ END ___________________ main.cpp ---------- START ------------------- #include "linear_inh_test.h" #include <cassert> #include <boost/mpl/vector.hpp> int main() { using namespace boost; typedef mpl::vector<pair_c<0, int>, pair_c<1, int>, pair_c<2, int> > my_vector; linear_inherited<my_vector> test_instance; int& ref0 = test_instance.nth_field<0>(); ref0 = 0; int& ref1 = test_instance.nth_field<1>(); ref1 = 1; int& ref2 = test_instance.nth_field<2>(); ref2 = 2; assert( test_instance.nth_field<0>() != test_instance.nth_field<1>() != test_instance.nth_field<2>() ); return 0; } __________ END ___________________ With Kind Regards, Ovanes Markarian On Tue, January 9, 2007 21:51, Khalil Shalish wrote: position in the type sequence. Something like this:
int field_0 = get_field<0>(in3comp); //This returns the first int data field. int field_1 =
get_field<1>(int3comp);
I am very new to C++ template programming and any help on this will be very much appreciated.
Thank you, Khalil Shalish kshalish@austin.rr.com _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
With Kind Regards, Ovanes

Hello,
I created the following composite class using mpl::inherit_linearly:
template <class T> struct DataField { T data; }
typedef mpl::inherit_linearly< mpl::vector< int, int, int> mpl::inherit< DataField<_2>, _1 >
Int3Composite;
Int3Composite int3comp;
Since the type of each data field is an int, I cannot use the type of the field to access the data in the field.
Q: Is there a way to write a template (call it get_field) to access the data using numeric
Ahh, sorry I also forget to mention, to make linear derivation as you wish, you must always produce a unique type, which is ensured with the pair_c construct. Otherwise you get the following simplified scenario: template <class T> struct DataField { T data; }; class SomeClass : public DataField<int>, DataField<int>, DataField<int> { ... }; In such a case compiler will produce a warning, which states that it will only derive once from DataField<int>. With Kind Regards, Ovanes -----Original Message----- From: Ovanes Markarian [mailto:om_boost@keywallet.com] Sent: Wednesday, January 10, 2007 9:30 PM To: boost-users@lists.boost.org Subject: Re: [Boost-users] [boost.mpl] Implementing a numeric index access to fields of a composite class created with mpl::inherit_linearly Hi! you could use an mpl::pair type to produce a static mapping of int value to type: mpl::pair<mpl::int_<0>, int> This is a little bit ugly, to write such a big construct, so you can write the following construct template<int N, class T> struct pair_c : mpl::pair<mpl::int_<N>, T> {}; Actually pair_c could be your DataField struct, so you can add the T instance to it: template<int N, class T> struct pair_c : mpl::pair<mpl::int_<N>, T> { T dataField; }; Now you can define a vector of pair types as follows: mpl::vector<pair_c<0, int>, pair_c<1, int>, pair_c<2, int> > my_vector; we use in this sample pair_c to make any type unique, dependent on the position in the vector. The next step would be to define the class with linear inheritance: template<class Seq> struct linear_inherited : boost::mpl::inherit_linearly < Seq , boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2> >::type {}; But now you would need the access function. I suggest to integrate this function as a linear_inherited member: template<class Seq> struct linear_inherited : boost::mpl::inherit_linearly < Seq , boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2> >::type { template<long N> typename boost::mpl::at_c<Seq, N>::type::second& nth_field() { typedef typename boost::mpl::at_c<Seq, N>::type* ptr_type; ptr_type ptr = static_cast<ptr_type>(this); return ptr->dataField; } }; When this function is a member you save some effor on passing the sequence type to its specialization, otherwise it will not know which type is meant. Let me explain this function: mpl has the at metafunction, which can access the Nth element of a static vector. Here this function is used to calculate the result_type (in our case it is always int, but we want to be generic ;), so you can make pair_c<0, double>, pair_c<1, SomeStruct> etc.). The at metafunction returns the type which was in the vector at this position, in our case this type is pair_c. Now we need to access the field type T. mpl::pair is defined as template <class X, class Y> struct pair { typedef X first; typedef Y second; }; so, the type of our datafield in pair_c is of type second. Therefore the function nth_field returns reference to second. In the function itself we use the static_cast operator to calculate the offset to our datafield within the class. And then we return the the field contained there. Below is the full listing I used to test and compile the scenario: linear_inh_test.h ---------- START ------------------- #ifndef __OM_LINEAR_INHERITANCE_TEST_H__ #define __OM_LINEAR_INHERITANCE_TEST_H__ #include <boost/mpl/at.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/pair.hpp> #include <boost/mpl/lambda.hpp> #include <boost/mpl/inherit.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/inherit_linearly.hpp> template<int N, class T> struct pair_c : boost::mpl::pair<boost::mpl::int_<N>, T> { T dataField; }; template<class Seq> struct linear_inherited : boost::mpl::inherit_linearly < Seq , boost::mpl::inherit<boost::mpl::_1, boost::mpl::_2> >::type { template<long N> typename boost::mpl::at_c<Seq, N>::type::second& nth_field() { typedef typename boost::mpl::at_c<Seq, N>::type* ptr_type; ptr_type ptr = static_cast<ptr_type>(this); return ptr->dataField; } }; #endif __________ END ___________________ main.cpp ---------- START ------------------- #include "linear_inh_test.h" #include <cassert> #include <boost/mpl/vector.hpp> int main() { using namespace boost; typedef mpl::vector<pair_c<0, int>, pair_c<1, int>, pair_c<2, int> > my_vector; linear_inherited<my_vector> test_instance; int& ref0 = test_instance.nth_field<0>(); ref0 = 0; int& ref1 = test_instance.nth_field<1>(); ref1 = 1; int& ref2 = test_instance.nth_field<2>(); ref2 = 2; assert( test_instance.nth_field<0>() != test_instance.nth_field<1>() != test_instance.nth_field<2>() ); return 0; } __________ END ___________________ With Kind Regards, Ovanes Markarian On Tue, January 9, 2007 21:51, Khalil Shalish wrote: position in the type sequence. Something like this:
int field_0 = get_field<0>(in3comp); //This returns the first int data field. int field_1 =
get_field<1>(int3comp);
I am very new to C++ template programming and any help on this will be
very much appreciated.
Thank you, Khalil Shalish kshalish@austin.rr.com _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
With Kind Regards, Ovanes _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (1)
-
Ovanes Markarian