9

我在这里和其他网站上也搜索了很多,但我没有找到令人满意的东西。

我需要的是非常简单的任务 - 实质上是在 C++ 中构造 ORDER BY 运算符。这意味着我有许多不同数据类型成员的结构,我需要一个比较器,它的成员和排序是可配置的。这是我的伪代码想法:

comparator.add(&MyStruct::member1, std::less);
comparator.add(&MyStruct::member2, std::greater);
std::sort(my_vector.begin(), my_vector.end(), comparator);

我得到按 member1 排序的数据,如果它是相同的 member2 决定,依此类推。

我不太擅长 stl 和模板,但我可以阅读和破译一些代码,发现这是非常合适的解决方案:https ://stackoverflow.com/a/11167563

不幸的是,在我的工作中,我必须使用带有错误的 32 位编译器的 c++ 构建器,它拒绝编译这个正确的代码。它 几乎不支持 c++11的任何内容,它有 boost 1.39 可用。

有人有任何解决方案可以在我可用的资源的情况下为我工作吗?先感谢您

编辑:

我得到了非常专业的解决方案,其中包含我知道的硬写比较运算符,并且在这里不太好用。我在我的问题中错过了这个。我的结构至少有 15 个成员,正如我所写,我需要经常更改成员/列的单独排序方向(asc、desc)。同样,我也需要经常更改排序成员的集合,就像 sql 中的按运算符排序一样。我也不能使用 stable_sort 之类的东西,因为我只是为某些类的 OnCompare 事件编写比较器。

4

3 回答 3

4

这不是太难。首先,考虑“规范”排序关系:

struct Compare
{
    bool operator()( C const& lhs, C const& rhs ) const
    {
        return lhs.a < rhs.a
            || ( !(rhs.a < lhs.a) && lsh.b < rhs.b )
            || ( !(rhs.a < lhs.a) && !(rhs.b < lhs.b) && lhs.c < rhs .c )
            || ...
    }
};

显然,没有人会真正写出这样的东西,但它完全符合对所需内容的正式定义。

当然,如果我们可以将数据成员想象为一个数组,我们可以将其重写为一个循环,利用之前!(rhs[i-1] < lsh[i-1]在每种情况下建立的优势:

struct Compare
{
    bool operator()( C const& lhs, C const& rhs ) const
    {
        int i = 0;
        while ( i != N && !(lhs[i] < rhs[i]) && !(rhs[i] < lhs[i]) ) {
            ++ i;
        }
        return i != N && lhs[i] < rhs[i];
    }
};

或者,如果所有元素都是全序的,那么==在它们上也定义了 ,我们可以假设它对应于弱偏序建立的等价关系:

struct Compare
{
    bool operator()( C const& lhs, C const& rhs ) const
    {
        int i = 0;
        while ( i != N && !(lhs[i] == rhs[i]) ) {
            ++ i;
        }
        return i != N && lhs[i] < rhs[i];
    }
};

剩下的就是以某种方式将其转换为可以处理任意类型元素的任意顺序的东西。有句老话,每个问题的解决方案都是额外的间接级别,它适用于这里。

首先,我们需要一些方法来处理每个元素的不同类型。多态性似乎是合适的(尽管如果在编译时评估元素的顺序是固定的,则可以使模板工作):

struct CompareOneElementOfC
{
    virtual bool isLessThan( C const& lhs, C const& rhs) const = 0;
    virtual bool isEqual( C const& lhs, C const& rhs) const = 0;
};

template <typename T, T C::*ptr>
struct ConcreteCompareOneElementOfC : public CompareOneElementOfC
{
    virtual bool isLessThan( C const& lhs, C const& rhs) const
    {
        return lhs.*ptr < rhs.*ptr;
    }
    virtual bool isEqual( C const& lhs, C const& rhs) const
    {
        return lhs.*ptr == rhs.*ptr;
    }
};

根据元素的类型,您可能需要手写特定的具体实例。如果任何元素不支持总排序,则必须省略 isEqual, 并相应地修改以下代码。

到目前为止,我们需要每个具体比较的一个静态实例:

ConcreteCompareOneElementOfC<int, &C::a> const c1;
ConcreteCompareOneElementOfC<double, &C::b> const c2;
//  ...

最后,将这些实例的地址放在一个表中:

CompareOneElementOfC const* const cmp[] = { &c1, &c2 ... };

您可以为不同的订单设置不同的表。如果只有几个,为每个定义静态表,并完成它。如果排序可以是任意的,请在每次排序之前以所需的顺序动态创建表。

最后:

class Compare
{
    CompareOneElementOfC const* const* begin;
    CompareOneElementOfC const* const* end;
public:
    template< size_t N >
    Compare( CompareOneElementOfC const* const (&cmp)[N] )
        : begin( cmp )
        , end( cmp + N )
    {
    }
    bool
    operator()( C const& lhs, C const& rhs ) const
    {
        auto current = begin;
        while ( current != end && (*current)->isEqual( lhs, rhs ) ) {
            ++ current;
        }
        return current != end && (*current)->isLessThan( lhs, rhs );
    }
}

(请注意,我还没有实际测试过这段代码,所以可能存在拼写错误和其他错误。不过,基本思想应该在那里。)

于 2013-09-13T09:05:33.017 回答
1

我认为只是重载operator <对你有用。

struct Struct {
    int member1;
    int member2;

    bool operator<(const Struct& rhs) const {
        if (member1 != rhs.member1)
            return member1 < rhs.member1
        else
            return member2 > rhs.member2
    }
};

这样,每当比较 的任何 2 个实例时Struct,它们都将通过 中定义的比较函数进行比较operator <

所以一个简单的std::sort(vec.begin(), vec.end())就行了!

编辑:

否则,您始终可以定义一个可用于比较每个元素的函子。这只是一个operator ()用于比较的重载类。

class ComparisonClass {
public:
    bool operator()(const Struct& lhs, const Struct& rhs) {
        if (lhs.member1 != rhs.member1)
            return lhs.member1 < rhs.member1
        else
            return lhs.member2 > rhs.member2
    }
};

您还可以定义一些ComparisonClass定义比较顺序的成员值。

使用它会这样称呼它std::sort(vec.begin(), vec.end(), ComparisonClass());

编辑2:

稍微复杂的代码 -

class ComparisonClass {
public:
    bool operator()(const Struct& lhs, const Struct& rhs) {
        for(int i=0; i<m_comparisonOrder.size(); i++) {
            int pos = m_comparisonOrder[i];
            if (lhs[pos] != rhs[pos]) {
                if (m_comparisonType[pos])
                    return lhs[pos] < rhs[pos];
                else
                    return lhs[pos] > rhs[pos];
            }
        }
    }

    std::vector<int> m_comparisonOrder.
    std::vector<bool> m_comparisonType;
};

在这里,我假设Struct有一个operator []返回适当的成员变量。

于 2013-09-13T08:10:28.783 回答
0

为什么不具有一个专门的比较器功能,它首先检查member1,如果相等则检查member2

喜欢

bool comparator(const MyStruct& s1, const MyStruct& s2)
{
    if (s1.member1 == s2.member1)
        return s1.member2 > s2.member2;
    else
        return s1.member1 < s2.member1;
}
于 2013-09-13T08:07:05.097 回答