大POD作为元组进行排序

Large POD as tuple for sorting

本文关键字:排序 元组 POD      更新时间:2023-10-16

我有一个POD,大约有30个不同类型的成员,我想在一个容器中存储数千个POD,然后按其中一个成员对该容器进行排序。

例如:

 struct Person{
   int idNumber;
   ....many other members
 }

我想按idNumber或我选择排序的任何其他成员排序的数千个Person对象。

我今天已经研究了一段时间,似乎最有效的,或者至少,最简单的解决方案是根本不使用struct,而是使用tuple,我可以将索引号传递给自定义比较函子,以便在std::sort中使用。(本页的一个示例展示了一种容易实现这种类型排序的方法,但它是在struct的单个成员上实现的,这将使模板化不那么容易,因为您必须通过名称引用成员,而不是通过tuple提供的索引。)

关于这种方法,我的问题分为两个部分:1)一个元组相当大,有几十个成员,这是可以接受的吗?2)是否有一个同样优雅的解决方案,继续使用struct而不是tuple ?

您可以创建一个比较器,它在内部存储一个指向成员的指针,以便它知道使用哪个成员进行比较:

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)是否可以接受一个相当大的元组,有几十个成员?

可以接受。然而,它并不容易维护,因为您需要处理的只是元组中的索引,这非常类似于一个神奇的数字。您所能得到的最好结果是使用enum重新引入名称到索引的映射,这也很难维护。

2)是否有一个同样优雅的解决方案,继续使用结构体而不是元组?

你可以很容易地写一个模板函数来访问一个特定的结构体成员(公平地说,我没有花太多的精力在这上面,它更多的是一个概念的证明,而不是其他的,所以你知道它是如何做到的):

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;
}
从这里开始,编写一个通用比较器就很容易了,您可以在闲暇时使用它(我将把它作为练习留给您)。这样,您仍然可以按名称引用成员,但不需要为每个成员编写单独的比较器。

您可以使用模板来提取排序键:

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,这是一个非常强大的容器,如果你想按不同的键索引(排序)对象。

创建一个类,该类可以使用指向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;
};