C++ 如何将 std::sort 与结构向量和比较函数一起使用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/328955/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use std::sort with a vector of structures and compare function?
提问by diminish
Thanks for a solution in C, now I would like to achieve this in C++ using std::sort and vector:
感谢C 中的解决方案,现在我想使用 std::sort 和 vector 在 C++ 中实现这一点:
typedef struct
{
double x;
double y;
double alfa;
} pkt;
vector< pkt > wektor;
filled up using push_back(); compare function:
vector< pkt > wektor;
使用 push_back() 填充;比较功能:
int porownaj(const void *p_a, const void *p_b)
{
pkt *pkt_a = (pkt *) p_a;
pkt *pkt_b = (pkt *) p_b;
if (pkt_a->alfa > pkt_b->alfa) return 1;
if (pkt_a->alfa < pkt_b->alfa) return -1;
if (pkt_a->x > pkt_b->x) return 1;
if (pkt_a->x < pkt_b->x) return -1;
return 0;
}
sort(wektor.begin(), wektor.end(), porownaj); // this makes loads of errors on compile time
What is to correct? How to use properly std::sort in that case?
纠正什么?在这种情况下如何正确使用 std::sort ?
回答by Konrad Rudolph
std::sort
takes a different compare function from that used in qsort
. Instead of returning –1, 0 or 1, this function is expected to return a bool
value indicating whether the first element is less than the second.
std::sort
采用与 中使用的比较函数不同的比较函数qsort
。此函数不返回 –1、0 或 1,而是返回一个bool
值,指示第一个元素是否小于第二个元素。
You have two possibilites: implement operator <
for your objects; in that case, the default sort
invocation without a third argument will work; or you can rewrite your above function to accomplish the same thing.
你有两种可能性:operator <
为你的对象实现;在这种情况下,sort
没有第三个参数的默认调用将起作用;或者你可以重写上面的函数来完成同样的事情。
Notice that you have to use strong typing in the arguments.
请注意,您必须在参数中使用强类型。
Additionally, it's good not to use a function here at all. Instead, use a function object. These benefit from inlining.
此外,最好不要在这里使用函数。相反,使用函数对象。这些受益于内联。
struct pkt_less {
bool operator ()(pkt const& a, pkt const& b) const {
if (a.alfa < b.alfa) return true;
if (a.alfa > b.alfa) return false;
if (a.x < b.x) return true;
if (a.x > b.x) return false;
return false;
}
};
// Usage:
sort(wektor.begin(), wektor.end(), pkt_less());
回答by Johannes Schaub - litb
In C++, you can use functors like boost::bind
which do this job nicely:
在 C++ 中,你可以使用像boost::bind
这样的函子来很好地完成这项工作:
#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));
}
If you need to do this many times, you can also solve the problem by making a function object which accepts member pointers and does the sort. You can reuse it for any kind of object and members. First how you use it:
如果你需要多次这样做,你也可以通过创建一个接受成员指针并进行排序的函数对象来解决问题。您可以将其重用于任何类型的对象和成员。首先你如何使用它:
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));
}
Here is the code for make_cmp. Feel free to rip it (using boost::preprocessor
):
这是 make_cmp 的代码。随意翻录它(使用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
回答by Christopher Oezbek
With C++0x and lambdas Konrad's solution looks like this:
使用 C++0x 和 lambdas,康拉德的解决方案如下所示:
sort(wektor.begin(), wektor.end(), [](pkt const& a, pkt const& b)
{
if (a.alfa < b.alfa) return true;
if (a.alfa > b.alfa) return false;
if (a.x < b.x) return true;
if (a.x > b.x) return false;
return false;
});