我有一个POD,有大约30个不同类型的成员,我想要将数千个POD存储在一个容器中,然后由其中一个成员对该容器进行排序。
例如:
struct Person{
int idNumber;
....many other members
}
我希望按Person
或我选择排序的任何其他成员排序的数千个idNumber
个对象。
我今天已经研究了一段时间了,似乎最有效,或者至少是最简单的解决方案就是根本不使用struct
,而是使用tuple
我可以将索引号传递给自定义比较函数,以便在std::sort
中使用。 (this page上的示例显示了一种轻松实现此类排序的方法,但是对struct
的单个成员执行此操作会使得模板化不那么容易,因为您必须通过以下方式引用成员:名称,而不是tuple
提供的索引。)
关于这种方法我的两部分问题是:1)一个元组是否可以接受相当大,有几十个成员? 2)是否有同样优雅的解决方案继续使用struct
代替tuple
?
答案 0 :(得分:6)
您可以制作一个比较器,用于存储指向成员的指针,以便它知道要进行比较的成员:
struct POD {
int i;
char c;
float f;
long l;
double d;
short s;
};
template<typename C, typename T>
struct Comp {
explicit Comp(T C::* p) : ptr(p) {}
bool operator()(const POD& p1, const POD& p2) const
{
return p1.*ptr < p2.*ptr;
}
private:
T C::* ptr;
};
// helper function to make a comparator easily
template<typename C, typename T>
Comp<C,T> make_comp( T C::* p)
{
return Comp<C,T>(p);
}
int main()
{
std::vector<POD> v;
std::sort(v.begin(), v.end(), make_comp(&POD::i));
std::sort(v.begin(), v.end(), make_comp(&POD::d));
// etc...
}
为了进一步概括这一点,让make_comp
采用自定义比较器,这样你就可以进行大于和等比较。
答案 1 :(得分:3)
1)元组是否可以接受相当大,有几十个成员?
是的,这是可以接受的。然而,它将不容易维护,因为您必须使用的是元组内的索引,这非常类似于幻数。您可以获得的最好效果是使用enum
重新引入名称到索引的映射,这也难以维护。
2)是否有一个同样优雅的解决方案继续使用struct而不是元组?
您可以轻松编写模板函数来访问特定的结构成员(公平地说,我没有付出太多努力,它更像是一个概念证明而不是其他任何东西,因此您可以了解它是如何形成的完成):
template<typename T, typename R, R T::* M>
R get_member(T& o) {
return o.*M;
}
struct Foo {
int i;
bool j;
float k;
};
int main() {
Foo f = { 3, true, 3.14 };
std::cout << get_member<Foo, float, &Foo::k>(f) << std::endl;
return 0;
}
从那里开始,编写一个可以随意使用的通用比较器同样容易(我会把它作为练习留给你)。这样你仍然可以通过名字引用你的成员,但你不需要为每个成员编写一个单独的比较器。
答案 2 :(得分:1)
您可以使用模板提取排序键:
struct A
{
std::string name;
int a, b;
};
template<class Struct, typename T, T Struct::*Member>
struct compare_member
{
bool operator()(const Struct& lh, const Struct& rh)
{
return lh.*Member < rh.*Member;
}
};
int main()
{
std::vector<A> values;
std::sort(begin(values), end(values), compare_member<A, int, &A::a>());
}
如果你想用不同的键索引(排序)对象,也许你想看看boost::multi_index_container这是一个非常强大的容器。
答案 3 :(得分:0)
创建一个类,该类可以使用指向Person
成员数据的指针进行比较:
std::sort(container.begin(), container.end(), Compare(&Person::idNumber));
Compare
的位置:
template<typename PointerToMemberData>
struct Compare {
Compare(PointerToMemberData pointerToMemberData) :
pointerToMemberData(pointerToMemberData) {
}
template<typename Type
bool operator()(Type lhs, Type rhs) {
return lhs.*pointerToMemberData < rhs.*pointerToMemberData
}
PointerToMemberData pointerToMemberData;
};