struct data { unsigned int a_ ; int b_ ; int c_ ; int d_ ; } ; bool operator<(const data & a1, const data & a2) { // a_, b_ d_ if (a1.a_ != a2.a_) return a1.a_ < a2.a_ ; if (a1.b_ != a2.b_) return a1.b_ < a2.b_ ; return a1.d_ < a2.b_ ; } #include <boost/tuple/tuple_comparison.hpp> bool s(foo const &l, foo const &r) { return boost::tie(la, lb, lc, ld) < boost::tie(ra, rb, rc, rd); } &data::a_, &data::b_, &data::d_ unsigned int data::*, int data::*, int data::* vector<int, char, double> v(1, '1', 1.0) ; vector<unsigned int data::*, int data::*, int data::*> v2(&data::a_, &data::b_, &data::d_) ; fusion::make_vector : make_vector(&data::a_, &data::b_, &data::d_) ; bool operator<(const data & a1, const data & a2) { return less_members(boost::fusion::make_vector(&data::a_, &data::b_, &data::d_), a1, a2) ; } a1 and a2 . In Boost.Fusion there is a fusion::transform function, similar to std::transform , - it applies the specified transformation to each element of the tuple. The difference is that in fusion::transform the output can be a tuple of completely different types! Only the number of elements will match.(&data::a_, &data::b_, &data::d_) to get a tuple (a1.a_, a1.b_, a1.d_) , moreover consisting of constant links. It turns out that the conversion must take a value of type RT::* and return a value of type const R & . In addition, it must “remember” the object with which it deals, from which it acquires these values. template <class S> struct member_getter { member_getter(const S & obj): obj_(obj) {} template <class R> const R & operator()(RS::* pmemb) const { return obj_.*pmemb ; } const S & obj_ ; } ; member_getter is a functor (an object with a specific operator "parentheses"), which is constructed with the object from which to extract values by the pointers to the fields. It works as follows: const data d = { 1U, 2, 3, 4 } ; member_getter<data> getter(d) ; const unsigned int & ra = getter(&data::a_) ; const int & rb = getter(&data::b_) ; fusion::transform determine the type of elements of the output tuple? For this there is a mechanism result_of , which is widely used in Boost. In order for result_of<member_getter<S>(RT::*)>::type be equal to const R & , you need to add the definition of the metafunction result to our member_getter , which will be addressed by the standard result_of implementation: template <class S> struct member_getter { member_getter(const S & obj): obj_(obj) {} template <class T> struct result ; template <class R> struct result<member_getter(RS::*)> { typedef const R & type ; } ; template <class R> struct result<member_getter(RS::* const &)> { typedef const R & type ; } ; template <class R> const R & operator()(RS::* pmemb) const { return obj_.*pmemb ; } const S & obj_ ; } ; result , only work with pointers to the member is supported. If you try to use member_getter to convert an element of some other type, a compilation error will occur.less_members : template <class T, class S> bool less_members(const T & membs, const S & a1, const S & a2) { using boost::fusion::transform ; return transform(membs, member_getter<S>(a1)) < transform(membs, member_getter<S>(a2)) ; } result_of and fusion::transform . In normal life, the way with boost::tie more suitable, since it has less overhead and it is simpler.Source: https://habr.com/ru/post/89874/
All Articles