1

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

例如:

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

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

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

我对这种方法的两部分问题是 1) 一个包含几十个成员的元组是否可以接受?和 2) 是否有一个同样优雅的解决方案可以继续使用struct而不是tuple为此?

4

4 回答 4

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请使用自定义比较器,以便您可以进行大于和其他比较。

于 2013-05-21T07:49:50.483 回答
3

1)一个元组相当大,有几十个成员是否可以接受?

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

2)是否有一个同样优雅的解决方案可以继续使用 struct 而不是 tuple 呢?

您可以轻松地编写一个模板函数来访问特定的结构成员(公平地说,我没有付出太多努力,它比其他任何东西都更像是一个概念证明,以便您了解如何完成它):

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;
}

从那里开始,编写一个通用比较器同样容易,您可以在闲暇时使用它(我将把它留给您作为练习)。这样您仍然可以按名称引用您的成员,但您不需要为每个成员编写单独的比较器。

于 2013-05-21T07:47:10.063 回答
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这是一个非常强大的容器。

于 2013-05-21T07:51:56.303 回答
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;
};
于 2013-05-21T07:58:22.893 回答