Boost库中的函数对象
来源:互联网 发布:英语对话软件 编辑:程序博客网 时间:2024/06/05 06:32
《C++11/14高级编程:Boost程序库探秘》笔记
函数对象是一个定义了operator()的类,可以像普通函数一样被调用,又具有类的功能。
hash
散列函数,主要被用于实现各种无序散列容器。位于名字空间boost,头文件<boost/functional/hash.cpp>,它是一个非常简单的函数对象,类摘要如下:
template<class T>struct hash: std::unary_function<T,std::size_t> //标准单参函数对象{ std::size_t operator()(T const& val) const;};
hash对C++数据类型支持非常全面,包括以下几种类型:
- char/wchar_t(但不支持C++11的char16_t/char32_t)
- short/int/long等各种整数类型
- bool类型
- float/double等浮点数类型
- long long和long double
- 指针和数组
- std::string/std::wstring
- 扩展支持pair、complex结构和array、vector、list等标准容器
除以上外,hash库不支持其他类型,包括标准容器适配器(stack、queue、priority_queue)和所有boost容器。
用法很简单,只需要创建一个实例,然后像使用函数一样调用它的operator()就行:
cout << hash<int>()(0x2000) << endl; //计算整数的散列值cout << hash<double>()(1.732) << endl; //计算浮点数的散列值cout << hash<const char*>()("string") << endl; //计算字符数组的散列值cout << hash<string>()("string") << endl; //计算标准字符串的散列值complex<double> c(1.0,2.0);cout << hash<decltype(c)>()(c) << endl; //计算复数的散列值map<int,string> m;cout << hash<decltype(m)>()(m) << endl; //计算标准映射容器的散列值array<int,5> ar;cout << hash<decltype(ar)>()(ar) << endl;//用于无序容器的模板参数boost::unordered_set<int,boost::hash<int> > us;boost::unordered_map<int,string,boost::hash<int> > um;
hash函数对象实际上只是一个简单的包装类,真正的散列值计算是在boost名字空间里的hash_value()函数实现,而hash_value()则针对各种数据类型定义了不同的重载,最后hash再对不同的类型使用模板特化来调用不同重载形式的hash_value()。
所以,如果需要实现对自定义类型计算散列值,那么只要在类中定义一个成员函数hash_value()并计算散列值,然后再在外部实现重载的自由函数hash_value(),比如:
class person final{private: int id; string name; unsigned int age;public: person(int a,const char* b,unsigned int c): id(a),name(b),age(c){} size_t hash_value() const //自定义的散列计算函数 { return hash<int>()(id); }};size_t hash_value(person const & p){ return p.hash_value();}//使用person p(1,"adam",20);cout << hash<person>()(p) << endl;
如果是要对多个目标计算散列值,那么可以使用hash库提供的辅助函数hash_combine()和hash_range()。
template<typename T>void hash_combine(size_t & seed,T const & v);template<typename It>std::size_t hash_range(It first,It last);template<typename It>void hash_range(std::size_t& seed,It first,It last);
hash_combine()使用一个变量seed作为初始输入参数,可以对多个变量连续调用,最终得到的散列值再从seed输出。散列值的计算与hash_combine的运算顺序有关,不同计算顺序得到散列值不同。
size_t hash_value() const{ size_t seed = 1984; //可以是任意整数 hash_combine(seed,id); hash_combine(seed,name); hash_combine(seed,age); return seed;}
hash_range()是另外一种组合散列值的方式,它对迭代器区间内的所有元素调用hash_combine()计算,如果不给初始seed赋值,seed默认为0。
mem_fn
同bind类似,可以调用对象或对象指针的任意成员函数或成员变量,支持多达8个参数,已被收入C++11标准。
同bind一样,mem_fn不是一个单一的模板函数,而是有很多重载以支持各种情况。它比较像一个简化版的bind,只能绑定类的成员函数或成员变量。
template<class R,class T> mf<R,T> mem_fn(R T::*f);template<class R,class T> class mf{public: R & operator()(T * p,...) const; //调用对象的指针 R & operator()(T & t,...) const; //调用对象的引用}
mem_fn不仅支持普通对象,也支持对象指针和只能指针,对于智能指针,mem_fn会使用boost::get_pointer()获取真正的指针,不会导致所有权转移或者引用计数增加,非常安全。
class demo_class{public: int x; demo_class(int a = 0):x(a){} void print() { cout << x << endl; } void hello(const char* str) { cout << str << endl; }}//使用mem_fndemo_class d(1);mem_fn(&demo_class::print)(d); //绑定普通对象,调用无参成员函数demo_class *p = &d;mem_fn(&demo_class::hello)(p,"hello"); //绑定对象指针,调用单参成员函数unique_ptr<demo_class> up(new demo_class(100));mem_fn(&demo_class::print)(up); //绑定unique_ptrassert(up.get() != 0); //指针的所有权没有转移shared_ptr<demo_class> sp(new demo_class);mem_fn(&demo_class::hello)(sp,"world");std::vector<demo_class> v(10);std::for_each(v.begin(),v.end(),mem_fn(&demo_class::print));cout << mem_fn(&demo_class::x)(d) << endl;
跟bind的对比,很多情况下,bind都可以代替mem_fn,需要增加一个”_1”占位符用于传递对象。
demo_class d;bind(&demo_class::print,_1)(d);bind(&demo_class::hello,_1,"hello")(&d);std::vector<demo_class> v(10);std::for_each(v.begin(),v.end(),bind(&demo_class::hello,_1,"world"));
factory
factory用函数对象封装了对象的创建过程,消除关键字new的随意使用,基本相当于new T(),可以直接创建T*指针,如果说checked_delete是智能delete,那么factory就是智能new。
template<typename Pointer, class Allocator,factory_alloc_propagation>class factory{public: typedef typename boost::remove_cv<Pointer>::type result_type; //函数对象调用后返回的类型,即创建的指针类型 typedef typename boost::pointee<result_type>::type value_type; //指针指向的值类型 inline result_type operator()()const; //最多支持10个参数 ...}
factory有三个模板参数,一般使用第一个模板参数Pointer,其他两个可以用缺省值。Pointer是被创建的“指针”类型,它不仅支持创建原始指针,也能够创建智能指针unique_ptr和shared_ptr。
使用的时候,factory要求被创建的类型T至少要有一个public的构造函数,否则无法访问不能完成创建工作。
//无参创建指针auto pi = factory<int*>()(); //两对括号auto ps = factory<string*>()();auto pp = factory<pair<int,double>*>()();
采用无参创建时factory将调用value_type的缺省构造函数完成对象初始化,由于factory不是函数而是函数对象,因此必须先用一对括号调用它的构造函数,创建出factory的一个临时对象,然后再用第二对括号调用它的operator()来创建所需的对象。
factory创建出的指针可以用delete操作符删除,当然最好用对应的checked_delete。
//创建智能指针auto up = factory<unique_ptr<int> >()();auto sp = factory<shared_ptr<string> >()();
创建智能指针要完全写出智能指针的类型,但注意不能创建boost:scoped_ptr,因为scoped_ptr不支持拷贝转移语义。
//带参数创建指针int a = 10,b = 20;auto pi = factory<int*>()(a);auto ps = factory<string*>()("char* lvalue"); //字符串是左值auto pp = factory<pair<int,int>*>()(a,b);auto pi2 = factory<int*>()(10); //使用右值,errorauto pp2 = factory<pair<int,int>*>()(1,2); //使用右值,error
带参数创建支持使用最多10个参数,参数将传递给类的构造函数完成初始化,但是缺陷是参数必须要是左值类型,传递右值无法编译,这将导致需要声明若干临时变量,麻烦。弥补的方法是使用bind包装factory函数对象,因为bind对参数类型没有限制,它内部持有的参数拷贝,可被用作左值,就是语法复杂一点 auto p = bind(factory<int*>(),10)();
value_factory
value_factory是factory库提供的另一个函数对象,同样可以创建对象,用法也和factory相似,只是它创建的是真正的对象实例,而不是指针。
template<typename T>class value_factory{public: typedef T result_type; inline result_type operator()() const;}
它的类声明和实现都比factory简单,仅有一个typedef,同样最多支持传入10个参数,也同样要求左值,但同样可以用bind解决右值问题,operator()将返回创建对象的拷贝,因此类型T必须支持拷贝构造。
auto i = value_factory<int>()();auto str = value_factory<string>()("hello");auto p = value_factory<pair<int,string>>()(i,str);auto i2 = bind(value_factory<int>(),10)();
- Boost库中的函数对象
- boost库中的split函数
- Boost学习------函数对象
- Boost 函数对象
- boost库随机函数中的bug
- boost函数对象的妙用
- Boost函数对象 boost.bind boost.function Boost.Ref Boost.Lambda
- Boost学习系列3-函数对象(上)
- Boost学习系列3-函数对象(下)
- boost python 函数中传递对象
- boost::function对象 convert 函数指针
- boost之路三 函数对象
- boost库--常见函数
- boost 中的 单元测试 库
- 【Boost】boost库中的小工具enable_shared_from_this
- boost中的range与slice函数简介
- Boost之高阶函数——函数对象
- boost库在工作(13)绑定器与函数对象之一
- Python (七)字典补充
- Hello
- AndroidImageSlider自定义其text的字体颜色样式
- 从 Python 到 Tensorflow 的运用
- 算法——插入排序
- Boost库中的函数对象
- hidden symbol ... is referenced by DSO
- TCP协议--带外数据和超时重传
- maven插件lombok
- Android基础——项目的文件结构(一)
- 洛谷1028 数的计算
- About
- x265 命令行参数大全
- oracle snapshot