定序谓词的链接(例如,对于std :: sort) [英] Chaining of ordering predicates (e.g. for std::sort)
问题描述
您可以将函数指针,函数对象(或boost lambda)传递给std :: sort,以定义要排序的容器的元素的严格弱排序。
但是,有时候(足够我打几次了),你想要能够链接原始的比较。
一个简单的例子将是如果您正在排序表示联系人数据的对象集合。有时您会想要按
姓,名,区号
进行排序。其他时间
姓氏
- 其他时间
年龄,名字,区号
p>
现在,你可以为每种情况编写一个附加的函数对象,但这违反了DRY原则 - 特别是如果每个比较都不太平凡。
看起来你应该能够写一个层次结构的比较函数 - 低层次的单一,原始,比较(例如名字<名字),然后更高层次称为低层次(可能用&&使用短路评估链接)来生成复合函数。
这种方法的麻烦是std: :sort接受一个二元谓词 - 谓词只能返回一个bool。所以,如果你正在撰写它们,你不能知道一个假是表示平等还是大于。你可以让你的低级谓词返回一个int,有三个状态 - 但是你必须将它们包装在更高级的谓词中,然后才能与std :: sort一起使用。
总之,这些不是不可逾越的问题。
因此,任何人都知道任何预先存在的库(如果它是一个std
[更新]
正如在一些评论中提到的 - 我已经开始编写自己的实现类来管理这个。这是相当最小的,可能有一些问题,一般。但在此基础上,对于任何感兴趣的人,该类位于此处:
http:// pastebin .com / f52a85e4f
有些帮助函数(避免需要指定模板参数)在这里:
你可以这样建立一个小链接系统:
struct Type {
string first,last;
int age
};
struct CmpFirst {
bool operator()(const Type& lhs,const Type& rhs){return lhs.first< rhs.first; }
};
struct CmpLast {
bool operator()(const Type& lhs,const Type& rhs){return lhs.last< rhs.last; }
};
struct CmpAge {
bool operator()(const Type& lhs,const Type& rhs){return lhs.age< rhs.age; }
};
template< typename首先,typename第二>
struct Chain {
Chain(const First& f_,const Second& s_):f(f_),s(s_){}
bool operator ; lhs,const Type& rhs){
if(f(lhs,rhs))
return true;
if(f(rhs,lhs))
return false;
return s(lhs,rhs);
}
template< typename Next>
Chain< Chain,Next> chain(const Next& next)const {
return Chain< Chain,Next> (* this,next);
}
第一f;
秒;
};
struct False {bool operator()(const Type& lhs,const Type& rhs){return false; }};
template< typename Op>
Chain< False,Op> make_chain(const Op& op){return Chain< False,Op> (False(),op); }
然后使用它:
vector< Type> v; // fill this baby up
sort(v.begin(),v.end(),make_chain(CmpLast())。chain(CmpFirst())。chain(CmpAge()));
最后一行是有点冗长,但我认为它的目的是清楚的。
You can pass a function pointer, function object (or boost lambda) to std::sort to define a strict weak ordering of the elements of the container you want sorted.
However, sometimes (enough that I've hit this several times), you want to be able to chain "primitive" comparisons.
A trivial example would be if you were sorting a collection of objects that represent contact data. Sometimes you will want to sort by
last name, first name, area code
. Other times
first name, last name
- yet other times
age, first name, area code
... etc
Now, you can certainly write an additional function object for each case, but that violates the DRY principle - especially if each comparison is less trivial.
It seems like you should be able to write a hierarchy of comparison functions - the low level ones do the single, primitive, comparisons (e.g. first name < first name), then higher level ones call the lower level ones in succession (probably chaining with && to make use of short circuit evaluation) to generate the composite functions.
The trouble with this approach is that std::sort takes a binary predicate - the predicate can only return a bool. So if you're composing them you can't tell if a "false" indicates equality or greater than. You can make your lower level predicates return an int, with three states - but then you would have to wrap those in higher level predicates before they could be used with std::sort on their own.
In all, these are not insurmountable problems. It just seems harder than it should be - and certainly invites a helper library implementation.
Therefore, does anyone know of any pre-existing library (esp. if it's a std or boost library) that can help here - of have any other thoughts on the matter?
[Update]
As mentioned in some of the comments - I've gone ahead and written my own implementation of a class to manage this. It's fairly minimal, and probably has some issues with it in general. but on that basis, for anyone interested, the class is here:
And some helper functions (to avoid the need to specify template args) is here:
You could build a little chaining system like so:
struct Type {
string first, last;
int age;
};
struct CmpFirst {
bool operator () (const Type& lhs, const Type& rhs) { return lhs.first < rhs.first; }
};
struct CmpLast {
bool operator () (const Type& lhs, const Type& rhs) { return lhs.last < rhs.last; }
};
struct CmpAge {
bool operator () (const Type& lhs, const Type& rhs) { return lhs.age < rhs.age; }
};
template <typename First, typename Second>
struct Chain {
Chain(const First& f_, const Second& s_): f(f_), s(s_) {}
bool operator () (const Type& lhs, const Type& rhs) {
if(f(lhs, rhs))
return true;
if(f(rhs, lhs))
return false;
return s(lhs, rhs);
}
template <typename Next>
Chain <Chain, Next> chain(const Next& next) const {
return Chain <Chain, Next> (*this, next);
}
First f;
Second s;
};
struct False { bool operator() (const Type& lhs, const Type& rhs) { return false; } };
template <typename Op>
Chain <False, Op> make_chain(const Op& op) { return Chain <False, Op> (False(), op); }
Then to use it:
vector <Type> v; // fill this baby up
sort(v.begin(), v.end(), make_chain(CmpLast()).chain(CmpFirst()).chain(CmpAge()));
The last line is a little verbose, but I think it's clear what's intended.
这篇关于定序谓词的链接(例如,对于std :: sort)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!