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