我在这里和其他网站上搜索了很多,但我还没有找到令人满意的东西。
我需要的是一项非常简单的任务 - 基本上可以在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 ++ builder,拒绝编译这个正确的代码。它确实support almost nothing from c++11,它提升了1.39。
有人有任何可用我的资源可以为我工作的解决方案吗?提前谢谢你
我得到了非常专业的解决方案,其中包括我所知道的难以编写的比较运算符,这些运算符在这里不起作用。我在我的问题中错过了这个。我的结构至少有15个成员,正如我写的,我需要经常更改成员/列的单独排序方向(asc,desc)。我也需要经常更改已排序成员的集合,就像在sql中按运算符顺序一样。我也不能使用类似stable_sort的东西,因为我只是为某些类的OnCompare事件编写比较器。
答案 0 :(得分: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];
}
};
或者,如果所有元素都是完全有序的,那么==
就是。{1}}
也定义了它们,我们可以假设它对应于
弱部分建立的等价关系
排序:
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 );
}
}
(请注意我实际上没有测试过这段代码,所以那里 可能是拼写错误和其他错误。仍然是基本的想法 应该在那里。)
答案 1 :(得分: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
}
};
这样,只要比较Struct
的任何2个实例,它们就会被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());
EDIT2:
稍微复杂一点的代码 -
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 []
,它返回相应的成员变量。
答案 2 :(得分: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;
}