Trong C++, bạn có thể sử dụng functors như boost::bind
mà làm công việc này độc đáo:
#include <vector>
#include <algorithm>
struct pkt {
double x;
double y;
double alfa;
pkt(double x, double y, double alfa)
:x(x), y(y), alfa(alfa) { }
};
int main() {
std::vector<pkt> p;
p.push_back(pkt(10., 0., 20.));
p.push_back(pkt(10, 0., 30.));
p.push_back(pkt(5., 0., 40.));
std::sort(p.begin(), p.end(),
boost::bind(&pkt::alfa, _1) < boost::bind(&pkt::alfa, _2) ||
boost::bind(&pkt::alfa, _1) == boost::bind(&pkt::alfa, _2) &&
boost::bind(&pkt::x, _1) < boost::bind(&pkt::x, _2));
}
Nếu bạn cần phải làm điều này nhiều lần, bạn cũng có thể giải quyết vấn đề bằng cách làm cho một đối tượng chức năng mà chấp nhận con trỏ thành viên và thực hiện sắp xếp. Bạn có thể tái sử dụng nó cho bất kỳ loại đối tượng và thành viên. Đầu tiên bạn sử dụng nó như thế nào:
int main() {
/* sorting a vector of pkt */
std::vector<pkt> p;
p.push_back(pkt(10., 0., 20.));
p.push_back(pkt(5., 0., 40.));
std::sort(p.begin(), p.end(), make_cmp(&pkt::x, &pkt::y));
}
Đây là mã cho make_cmp. Cảm thấy tự do để rip nó (sử dụng boost::preprocessor
):
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
// tweak this to increase the maximal field count
#define CMP_MAX 10
#define TYPEDEF_print(z, n, unused) typedef M##n T::* m##n##_type;
#define MEMBER_print(z, n, unused) m##n##_type m##n;
#define CTORPARAMS_print(z, n, unused) m##n##_type m##n
#define CTORINIT_print(z, n, unused) m##n(m##n)
#define CMPIF_print(z, n, unused) \
if ((t0.*m##n) < (t1.*m##n)) return true; \
if ((t0.*m##n) > (t1.*m##n)) return false; \
#define PARAM_print(z, n, unused) M##n T::* m##n
#define CMP_functor(z, n, unused) \
template <typename T \
BOOST_PP_ENUM_TRAILING_PARAMS(n, typename M)> \
struct cmp##n { \
BOOST_PP_REPEAT(n, TYPEDEF_print, ~) \
BOOST_PP_REPEAT(n, MEMBER_print, ~) \
cmp##n(BOOST_PP_ENUM(n, CTORPARAMS_print, ~)) \
BOOST_PP_IF(n, :, BOOST_PP_EMPTY()) \
BOOST_PP_ENUM(n, CTORINIT_print, ~) { } \
\
bool operator()(T const& t0, T const& t1) const { \
BOOST_PP_REPEAT(n, CMPIF_print, ~) \
return false; \
} \
}; \
\
template<typename T \
BOOST_PP_ENUM_TRAILING_PARAMS(n, typename M)> \
cmp##n<T BOOST_PP_ENUM_TRAILING_PARAMS(n, M)> \
make_cmp(BOOST_PP_ENUM(n, PARAM_print, ~)) \
{ \
return cmp##n<T BOOST_PP_ENUM_TRAILING_PARAMS(n, M)>( \
BOOST_PP_ENUM_PARAMS(n, m)); \
}
BOOST_PP_REPEAT(CMP_MAX, CMP_functor, ~)
#undef TYPEDEF_print
#undef MEMBER_print
#undef CTORPARAMS_print
#undef CTORINIT_print
#undef CMPIF_print
#undef PARAM_print
#undef CMP_functor
Bạn thậm chí không cần phải sử dụng một functor. Tại sao không chỉ sử dụng một chức năng bình thường, nó là ít dòng mã? –
Dave, lý do là functors có thể được inlined, kể từ khi các functors loại sẽ cho trình biên dịch mà chức năng được gọi là lúc biên dịch thời gian. bằng cách sử dụng con trỏ hàm, trình biên dịch chỉ biết điều này khi chạy, và nó không thể nội tuyến. –
@ onebyone.livejournal.com: Không đúng sự thật. Một con trỏ hàm không thể được inlined. Trình biên dịch không được phép thực hiện tối ưu hóa đó. (Mặc dù một con trỏ là một functor). –