这并不难。首先,考虑“规范”
排序关系:
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];
}
};
剩下的就是以某种方式将其转化为某种东西
可以处理任意元素的任意顺序
类型。有句老话,解决所有问题
是一个额外的间接级别,它适用于这里。
首先,我们需要一些方法来处理不同类型的
每个元素。多态性似乎是合适的(尽管
模板可以按照 if 的顺序工作
被评估的元素在编译时是固定的):
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 );
}
}
(请注意,我还没有实际测试过这段代码,所以有
可能是拼写错误和其他错误。还是基本思路
应该在那里。)