C++标准库扩展,查找元素,使用修饰者模式构造查询条件
2013-04-24 00:22
337 查看
C++标准库的的查找算法std::find_if 允许提供一个pred函数用于在容器内查找满足pred函数调用为真的元素。
同样以学生信息结构为例,常常会需要查找结构的某个成员是特定值的元素,比如查找所有计算机系的学生。
每次为这种特定需求写一个函数对象不够灵活,我们也希望通过一组通用的函数对象构造模板来实现。
下面这个函数对象用于比较对象的某个成员是否和输入的值相等:
对应上面函数对象的生成函数:
另外一组提供不等于的条件:
接下来就可以工作了:
但如果要支持更复杂的判断逻辑,比如and和or连接多个成员的比较函数呢
好像也不难,写出下面的函数对象定义:
感觉良好,如果再加一个条件呢,是不是就有点难以理解了。。。
更好的形式可能是这样的:
equal(&Person::strDepart, std::string("math"))
.and(equal(&Person::strClass, std::string("class1"))
.or_equal(&Person::strClass, std::string("class2")));
上面语句构造的条件查找的是数学系的,且班级是class1或者class2的学生。
分析上面的语句,看来生成函数equal或noequal返回的不能是简单的函数对象了,此函数对象还需要包含如下一些方法:
and
or
and_equal
or_equal
and_noequal
or_noequal
。。。
为每个函数对象都定义这么多方法吗,好像不是很容易的事,更简单的做法是使用修饰者模式写一个修饰类:
对应的,生成函数改造如下:
上面的生成函数使用LogicLink来修饰了原有的函数对象,达到在函数对象上增加and,or等连接操作的能力
剩下其它的几个方法感兴趣的同学可以实现下^^
4000
同样以学生信息结构为例,常常会需要查找结构的某个成员是特定值的元素,比如查找所有计算机系的学生。
每次为这种特定需求写一个函数对象不够灵活,我们也希望通过一组通用的函数对象构造模板来实现。
下面这个函数对象用于比较对象的某个成员是否和输入的值相等:
template<class TField, class TValue> struct FieldEqualPred { TField f_; //参与比较的数据成员指针 TValue v_; //比较的值 //比较函数 template<class T> bool operator ()(const T& l) { return l.*f_ == v_; } //构造函数 FieldEqualPred(TField f, const TValue &v) : f_(f),v_(v){} };
对应上面函数对象的生成函数:
template<class F, class V> FieldEqualPred<F,V> equal (F f, const V &v){ return FieldEqualPred<F,V>(f,v); }
另外一组提供不等于的条件:
template<class TField, class TValue> struct FieldNoEqualPred { TField f_; //参与比较的数据成员指针 TValue v_; //比较的值 //比较函数 template<class T> bool operator ()(const T& l) { return l.*f_ != v_; } //构造函数 FieldNoEqualPred(TField f, const TValue &v) : f_(f),v_(v){} }; template<class F, class V> FieldNoEqualPred<F,V> noequal(F f, const V &v){ return FieldNoEqualPred<F,V>(f,v); }
接下来就可以工作了:
int main() { std::vector<Person> persons; persons.push_back(Person("=xiaowang", "class3", "computer")); persons.push_back(Person("=xiaoli", "class1", "math")); persons.push_back(Person("=xiaozhu", "class2", "computer")); //查找年级是class1的学生 std::find_if(persons.begin(), persons.end(), equal(&Person::strClass, std::string("class1"))); return 0; }
但如果要支持更复杂的判断逻辑,比如and和or连接多个成员的比较函数呢
好像也不难,写出下面的函数对象定义:
template<class Pred1, class Pred2> struct LogicAndPred { Pred1 p1_; //左边的比较对象 Pred2 p2_; //右边的比较对象 //比较函数 template<class T> bool operator ()(const T& l) { return p1_(l) && p2_(l); } //构造函数 LogicAndPred(Pred1 &p1, Pred2 &p2) : p1_(p1),p2_(p2){} }; template<class Pred1, class Pred2> struct LogicOrPred { Pred1 p1_; //左边的比较对象 Pred2 p2_; //右边的比较对象 //比较函数 template<class T> bool operator ()(const T& l) { return p1_(l) || p2_(l); } //构造函数 LogicOrPred(Pred1 &p1, Pred2 &p2) : p1_(p1),p2_(p2){} }; template<class P1, class P2> LogicAndPred<P1,P2> and (P1 &p1, P2 &p2){ return LogicAndPred<P1,P2>(p1,p2); } template<class P1, class P2> LogicOrPred<P1,P2> or (P1 &p1, P2 &p2){ return LogicOrPred<P1,P2>(p1,p2); } int main() { std::vector<Person> persons; persons.push_back(Person("=xiaowang", "class3", "computer")); persons.push_back(Person("=xiaoli", "class1", "math")); persons.push_back(Person("=xiaozhu", "class2", "computer")); //查找数学系且年级是class1的学生 std::find_if(persons.begin(), persons.end(), and(equal(&Person::strDepart, std::string("math")), equal(&Person::strClass, std::string("class1")))); return 0; }
感觉良好,如果再加一个条件呢,是不是就有点难以理解了。。。
更好的形式可能是这样的:
equal(&Person::strDepart, std::string("math"))
.and(equal(&Person::strClass, std::string("class1"))
.or_equal(&Person::strClass, std::string("class2")));
上面语句构造的条件查找的是数学系的,且班级是class1或者class2的学生。
分析上面的语句,看来生成函数equal或noequal返回的不能是简单的函数对象了,此函数对象还需要包含如下一些方法:
and
or
and_equal
or_equal
and_noequal
or_noequal
。。。
为每个函数对象都定义这么多方法吗,好像不是很容易的事,更简单的做法是使用修饰者模式写一个修饰类:
template<class TField, class TValue, template<class T> class TPred> struct FieldPred { TField f_; //参与比较的数据成员指针 TValue v_; //比较的值 //构造函数 FieldPred(TField f, const TValue &v) : f_(f),v_(v){} //比较函数 template<class T> bool operator ()(const T& l) { return compare(l.*f_); } template<class T> bool compare(T &left) { return TPred<T>()(left, v_); } }; template<class Pred1, class Pred2, template<class T> class TPred> struct LogicPred { Pred1 p1_; //左边的比较对象 Pred2 p2_; //右边的比较对象 //构造函数 LogicPred(Pred1 &p1, Pred2 &p2) : p1_(p1),p2_(p2){} //比较函数 template<class T> bool operator ()(const T& l) { return TPred<bool>()(p1_(l), p2_(l)); } }; template<class TInner> struct LogicLink : TInner { LogicLink(TInner inner) : TInner(inner){} template<class F, class V> LogicLink<LogicPred<TInner, FieldPred<F,V,std::equal_to>, std::logical_and> > and_equal(F f, const V &v) { typedef LogicPred<TInner, FieldPred<F,V,std::equal_to>, std::logical_and> type; return type((TInner&)(*this), FieldPred<F,V,std::equal_to>(f,v)); } template<class P> LogicLink<LogicPred<TInner, P, std::logical_and> > and(P &p) { return LogicPred<TInner, P, std::logical_and>((TInner&)(*this), p); } };
对应的,生成函数改造如下:
template<class F, class V> LogicLink<FieldPred<F,V,std::equal_to> >equal(F f, const V &v){ return FieldPred<F,V,std::equal_to>(f,v); } template<class F, class V> LogicLink<FieldPred<F,V,std::not_equal_to> > noequal(F f, const V &v){ return FieldPred<F,V,std::not_equal_to>(f,v); }
上面的生成函数使用LogicLink来修饰了原有的函数对象,达到在函数对象上增加and,or等连接操作的能力
剩下其它的几个方法感兴趣的同学可以实现下^^
4000
相关文章推荐
- 通用查询的使用模式--基本条件输入
- Jeecg中使用<t: dgCol>标签的自动构造查询条件时出现类型转换错误的解决办法。
- 使用PDF.NET数据开发框架的实体操作语言OQL构造复杂查询条件
- Linq多条件查询优化---使用扩展方法
- Hibernate-Criteria查询(3)DetachedCriteria构造查询条件、命名查询、原生SQL、调用存储过程(使用JDBC)
- 水晶报表问题汇总(水晶报表的使用与查询条件生成报表、注册码、打印问题、模式使用示例、C#.Net的WinForm中的使用、程序发布与部署)
- JQuery里面的几种选择器 查找满足条件的元素$("#控件ID")
- 使用Java构造高可扩展应用(1)
- ORACLE——ROWNUM解析(使用ROWNUM大于条件,无法得到任何查询结果)
- pl/sql developer 查询语句无法使用中文条件
- 多个构造参数考虑使用Builder构造器模式
- 7、使用WHERE子句查询表中满足条件的记录
- 三层模式中,多条件查询中的sql语句拼接
- 使用表达式树动态构建Linq查询条件来实现单个实体动态查询
- 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma
- 菜鸟译文(二)——使用Java泛型构造模板方法模式
- SP报错内容:此查询使用不支持的元素,例如引用多个列表,或使用 EntityRef/EntitySet 投影完整实体
- MySql查询IF和CASE条件判断使用
- 在SQL查询语句中,使用条件where 1=2的意义
- 查找数组当中指定的信息([示例]NSPredicate基础-查询数组中符合条件的子集)