STL之仿函数实现详解
分类专栏: C PlusPlus STL源代码剖析 文章标签: STL 仿函数
版权
1、何为仿函数
仿函数的主要功能是为了搭配STL算法使用,单独使用仿函数的情况比较少。
仿函数(functors)在C++标准中采用的名称是函数对象(function objects)。仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求–函数指针无法和STL其他组件搭配,产生更灵活变化。仿函数本质就是类重载了一个operator(),创建一个行为类似函数的对象。
对于重载了()操作符的类,可以实现类似函数调用的过程,所以叫做仿函数,实际上仿函数对象仅仅占用1字节,因为内部没有数据成员,仅仅是一个重载的方法而已。实际上可以通过传递函数指针实现类似的功能,但是为了和STL内部配合使用,他提供了仿函数的特性。
struct MyPlus{
int operator()(const int &a , const int &b) const{
return a + b;
}
};
int main()
{
MyPlus a;
cout << MyPlus()(1,2) << endl;//1、通过产生临时对象调用重载运算符
cout << a.operator()(1,2) << endl;//2、通过对象显示调用重载运算符
cout << a(1,2) << endl;//3、通过对象类似函数调用 隐示地调用重载运算符
return 0;
}
这里写图片描述
在STL中,当需要传递仿函数对象的时候,通过采用上述第1种方法,因为传递进去仅仅为了给容器内部成员赋值,所以没有必要生成对象,产生临时对象即可。
2、STL中基础仿函数
1、仿函数定义自己型别
算法内部可能需要使用仿函数返回值或者输出值的类型参数,因此定义两个类。
//一元函数的参数和返回值类型,通常被继承
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
};
//二元函数的参数和返回值类型,通常被继承
template <class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
上述两个类分别定义了一元和二元函数参数和返回值型别,对应的仿函数类仅仅需要继承此类即可。
2、算术类仿函数
标准库给我们定义了一些通用的仿函数,可以直接调用,生成对象,面向用户。
//////算术类仿函数 + - * / %////////////////////////////////
//plus仿函数,生成一个对象,里面仅仅有一个函数重载的方法。
template <class T>
struct plus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x + y; }
};
//minus仿函数
template <class T>
struct minus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x - y; }
};
template <class T>
struct multiplies : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x * y; }
};
template <class T>
struct divides : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x / y; }
};
template <class T>
struct modulus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x % y; }
};
//取负值
template <class T>
struct negate : public unary_function<T, T> {
T operator()(const T& x) const { return -x; }
};
单独使用仿函数,通常将仿函数和算法部分单独分开使用。
#include <iostream> // std::cout
#include <functional> // std::plus
#include <algorithm> // std::transform
using namespace std;
int main(void)
{
cout << minus<int>()(10,5) << endl;//5
cout << multiplies<int>()(10,5) << endl;//50
cout << divides<int>()(10,5) << endl;//2
cout << modulus<int>()(10,5) << endl;//0
cout << negate<int>()(10) << endl;//-10
return 0;
}
这里写图片描述
3、关系运算符仿函数
//关系运算符仿函数
// x==y 仿函数
template <class T>
struct equal_to : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x == y; }
};
// x!=y 仿函数
template <class T>
struct not_equal_to : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x != y; }
};
// x>y 仿函数
template <class T>
struct greater : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x > y; }
};
// x<y 仿函数
template <class T>
struct less : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x < y; }
};
// x>=y 仿函数
template <class T>
struct greater_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x >= y; }
};
// x<=y 仿函数
template <class T>
struct less_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x <= y; }
};
// sort algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
#include <functional> // std::
bool myfunction (int i,int j) { return (i < j); }
int main () {
int myints[] = {32,71,12,45,26,80,53,33};
std::vector<int> myvector (myints, myints+8); // 32 71 12 45 26 80 53 33
// using default comparison (operator <):
std::sort (myvector.begin(), myvector.begin()+4); //(12 32 45 71)26 80 53 33
// using function as comp
std::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)
// using object as comp
std::sort (myvector.begin(), myvector.end(), std::less<int>()); //(12 26 32 33 45 53 71 80)
// print out content:
std::cout << "myvector contains:";
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
这里写图片描述
4、逻辑运算符仿函数
template <class T>
struct logical_and : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x && y; }
};
template <class T>
struct logical_or : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x || y; }
};
template <class T>
struct logical_not : public unary_function<T, bool> {
bool operator()(const T& x) const { return !x; }
};
5、证同、选择、投射仿函数
///////////////////////////////////////////////////////////////////////////////////////////
//证同仿函数,主要用于RB或者hashmap里面 key = value情况
template <class T>
struct identity : public unary_function<T, T> {
const T& operator()(const T& x) const { return x; }
};
//选择仿函数,主要用与RB和hashmap里面key 不为value情况,从pair种取出key
template <class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type> {
const typename Pair::first_type& operator()(const Pair& x) const
{
return x.first;
}
};
//选择仿函数,主要用与RB和hashmap里面key 不为value情况,从pair种取出value
template <class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type> {
const typename Pair::second_type& operator()(const Pair& x) const
{
return x.second;
}
};
//投射函数,输入x和y返回x
template <class Arg1, class Arg2>
struct project1st : public binary_function<Arg1, Arg2, Arg1> {
Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
};
//投射函数,输入x和y返回y
template <class Arg1, class Arg2>
struct project2nd : public binary_function<Arg1, Arg2, Arg2> {
Arg2 operator()(const Arg1&, const Arg2& y) const { return y; }
};
/////////////////////////////////////////////////////////////////////
3、STL中仿函数适配器
仿函数适配器是通过将上述仿函数重新配置成含有新功能的模板函数。
1、对仿函数返回值进行否定适配器
传入仿函数对象即可,和以前一样使用,仅仅包装了一下子而已。
//否定一元返回值
//模板参数传入仿函数类
template <class Predicate>
class unary_negate
: public unary_function<typename Predicate::argument_type, bool> {
protected:
Predicate pred;//对象
public:
explicit unary_negate(const Predicate& x) : pred(x) {}
bool operator()(const typename Predicate::argument_type& x) const {
return !pred(x);//这里是调用的关键
}
};
//辅助函数,使得我们方便使用unary_negate<Pred>
//传入对象,并返回临时对象。
template <class Predicate>
inline unary_negate<Predicate> not1(const Predicate& pred) {
return unary_negate<Predicate>(pred);//返回临时对象
}
//辅助函数,识别传入对象,通过模板萃取其模板型别,然后声明模板声明临时对象并用传入对象初始化。
/////////////////////////////////////////////////////////////////////////
//否定二元返回值
template <class Predicate>
class binary_negate
: public binary_function<typename Predicate::first_argument_type,
typename Predicate::second_argument_type,
bool> {
protected:
Predicate pred;
public:
explicit binary_negate(const Predicate& x) : pred(x) {}
bool operator()(const typename Predicate::first_argument_type& x,
const typename Predicate::second_argument_type& y) const {
return !pred(x, y);
}
};
template <class Predicate>
inline binary_negate<Predicate> not2(const Predicate& pred) {
return binary_negate<Predicate>(pred);
}
//not1 example
#include <iostream> // std::cout
#include <functional> // std::not1
#include <algorithm> // std::count_if
struct IsOdd {
bool operator() (const int& x) const {return x%2 == 1;}
typedef int argument_type;
};//类
int main () {
int values[] = {1,2,3,4,5};
int cx = std::count_if( values, values+5, std::not1(IsOdd()) );//找出不是奇数的个数
//IsOdd()产生临时对象a,not1返回临时对象并用a初始化。
std::cout << "There are " << cx << " elements with even values.\n";
return 0;
}
输出:
There are 2 elements with even values.
// not2 example
#include <iostream> // std::cout
#include <functional> // std::not2, std::equal_to
#include <algorithm> // std::mismatch
#include <utility> // std::pair
int main () {
int foo[] = {10,20,30,40,50};
int bar[] = {0,15,30,45,60};
std::pair<int*,int*> firstmatch,firstmismatch;
firstmismatch = std::mismatch (foo, foo+5, bar, std::equal_to<int>());//返回第一个不匹配数值
firstmatch = std::mismatch (foo, foo+5, bar, std::not2(std::equal_to<int>()));//返回第一个匹配的数值
std::cout << "First mismatch in bar is " << *firstmismatch.second << '\n';
std::cout << "First match in bar is " << *firstmatch.second << '\n';
return 0;
}
输出:
First mismatch in bar is 0
First match in bar is 30
2、将仿函数某个参数绑定为固定值的适配器
//////////////////////////////////////绑定参数,将二元函数某个参数绑定为恒定值///////////////////////////////////////
//Operation前面讲解的仿函数类
template <class Operation>
class binder2nd
: public unary_function<typename Operation::first_argument_type,
typename Operation::result_type> {
protected:
Operation op;//仿函数对象
typename Operation::second_argument_type value;//第二个参数类型
public:
binder2nd(const Operation& x,
const typename Operation::second_argument_type& y)
: op(x), value(y) {}//传入x是对象的引用,第二参数的引用
typename Operation::result_type
operator()(const typename Operation::first_argument_type& x) const {//传入x,底层调用op
return op(x, value);//将value绑定为op的第二个参数
}
};
//辅助函数,辅助产生绑定好的对象 bind2nd
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
typedef typename Operation::second_argument_type arg2_type;
return binder2nd<Operation>(op, arg2_type(x));//仅仅产生临时对象,可以传给模板函数
}
//第一个参数绑定起来
template <class Operation>
class binder1st
: public unary_function<typename Operation::second_argument_type,
typename Operation::result_type> {
protected:
Operation op;//操作
typename Operation::first_argument_type value;//第一个参数类型
public:
binder1st(const Operation& x,
const typename Operation::first_argument_type& y)
: op(x), value(y) {}//构造
typename Operation::result_type
operator()(const typename Operation::second_argument_type& x) const {
return op(value, x);
}
};
//辅助函数调用进行
template <class Operation, class T>
inline binder1st<Operation> bind1st(const Operation& op, const T& x) {
typedef typename Operation::first_argument_type arg1_type;
return binder1st<Operation>(op, arg1_type(x));
}
//////////////////////////////////////////////////////////////////////////////
// binder2nd example
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
int main () {
int numbers[] = {10,-20,-30,40,-50};
int cx;
int cx1;
binder2nd< less<int> > IsNegative (less<int>(),0);//将less<int>重新包装产生新的对象binder2nd
cx = count_if (numbers,numbers+5 , IsNegative);//二者用法一样
cx1 = count_if (numbers,numbers+5,bind2nd(less<int>() , 0));
cout << "There are " << cx <<" "<< cx1 << " negative elements.\n";
return 0;
}
这里写图片描述
3、将两个仿函数合并成一个仿函数的适配器
///////////////////////////////用于函数合成/////////////////////////////////////////////////
//一元仿函数合成操作
//h(x) = f( g(x) )
template <class Operation1, class Operation2>
class unary_compose : public unary_function<typename Operation2::argument_type,
typename Operation1::result_type> {
protected:
Operation1 op1;
Operation2 op2;
public:
unary_compose(const Operation1& x, const Operation2& y) : op1(x), op2(y) {}
typename Operation1::result_type
operator()(const typename Operation2::argument_type& x) const {
return op1(op2(x));//类似f(g(x))
}
};
template <class Operation1, class Operation2>
inline unary_compose<Operation1, Operation2> compose1(const Operation1& op1,
const Operation2& op2) {
return unary_compose<Operation1, Operation2>(op1, op2);//返回临时对象
}
//二元仿函数合成操作
//h(x) = f( g1(x) , g2(x) )
template <class Operation1, class Operation2, class Operation3>
class binary_compose
: public unary_function<typename Operation2::argument_type,
typename Operation1::result_type> {
protected:
Operation1 op1;
Operation2 op2;
Operation3 op3;
public:
binary_compose(const Operation1& x, const Operation2& y,
const Operation3& z) : op1(x), op2(y), op3(z) { }
typename Operation1::result_type
operator()(const typename Operation2::argument_type& x) const {
return op1(op2(x), op3(x));//返回临时对象
}
};
template <class Operation1, class Operation2, class Operation3>
inline binary_compose<Operation1, Operation2, Operation3>
compose2(const Operation1& op1, const Operation2& op2, const Operation3& op3) {
return binary_compose<Operation1, Operation2, Operation3>(op1, op2, op3);
}
4、将函数指针合并成仿函数的适配器
///////////////////////////////用于函数指针/////////////////////////////////////////////////
//将一元函数指针包装成仿函数
template <class Arg, class Result>
class pointer_to_unary_function : public unary_function<Arg, Result> {
protected:
Result (*ptr)(Arg);//函数指针变量
public:
pointer_to_unary_function() {}
explicit pointer_to_unary_function(Result (*x)(Arg)) : ptr(x) {}
Result operator()(Arg x) const { return ptr(x); }
};
template <class Arg, class Result>
inline pointer_to_unary_function<Arg, Result> ptr_fun(Result (*x)(Arg)) {
return pointer_to_unary_function<Arg, Result>(x);//传入函数指针、一元参数类型、返回值类型,返回一个仿函数对象
}
/////////////////////////////////////////////////////////
//将二元函数指针包装成仿函数
template <class Arg1, class Arg2, class Result>
class pointer_to_binary_function : public binary_function<Arg1, Arg2, Result> {
protected:
Result (*ptr)(Arg1, Arg2);
public:
pointer_to_binary_function() {}
explicit pointer_to_binary_function(Result (*x)(Arg1, Arg2)) : ptr(x) {}
Result operator()(Arg1 x, Arg2 y) const { return ptr(x, y); }
};
template <class Arg1, class Arg2, class Result>
inline pointer_to_binary_function<Arg1, Arg2, Result>
ptr_fun(Result (*x)(Arg1, Arg2)) {
return pointer_to_binary_function<Arg1, Arg2, Result>(x);//返回对象即可
}
// ptr_fun example
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <numeric>
using namespace std;
int main () {
char* foo[] = {"10","20","30","40","50"};
int bar[5];
int sum;
transform (foo, foo+5, bar, ptr_fun(atoi) );//将函数指针转换成仿函数对象,这里输入函数指针效果一样
transform (foo, foo+5, bar, atoi );
sum = accumulate (bar, bar+5, 0);
cout << "sum = " << sum << endl;
return 0;
}
输出:
sum = 150
5、将成员函数指针提取出来包装成仿函数适配器
//函数指针类别:返回S 无输入 通过指针调用
template <class S, class T>
class mem_fun_t : public unary_function<T*, S> {
public:
explicit mem_fun_t(S (T::*pf)()) : f(pf) {}//初始化
S operator()(T* p) const { return (p->*f)(); }//调用,p里面对应的函数
private:
S (T::*f)();//这是一个变量,这个函数指针变量
};
//辅助函数,直接通过模板萃取相应的型别,然后声明相应的对象
template <class S, class T>
inline mem_fun_t<S,T> mem_fun( S (T::*f)() ) {
return mem_fun_t<S,T>(f);//返回仿函数临时对象,真的很牛逼哦抽象出来了
}
//小例子
size_type length() const
{ return _M_string_length; }
mem_fun(&string::length);//传入函数指针,::优先级大于&
//s 是 size_type T是string f是length,通过模板萃取出这些型别,即可产生相应的对象。
//有一个参数,通过指针调用
template <class S, class T, class A>
class mem_fun1_t : public binary_function<T*, A, S> {
public:
explicit mem_fun1_t(S (T::*pf)(A)) : f(pf) {}
S operator()(T* p, A x) const { return (p->*f)(x); }
private:
S (T::*f)(A);
};
template <class S, class T, class A>
class const_mem_fun1_t : public binary_function<const T*, A, S> {
public:
explicit const_mem_fun1_t(S (T::*pf)(A) const) : f(pf) {}
S operator()(const T* p, A x) const { return (p->*f)(x); }
private:
S (T::*f)(A) const;
};
// mem_fun example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
int main () {
vector <string*> numbers;
// populate vector of pointers:
numbers.push_back ( new string ("one") );
numbers.push_back ( new string ("two") );
numbers.push_back ( new string ("three") );
numbers.push_back ( new string ("four") );
numbers.push_back ( new string ("five") );
vector<int> lengths(numbers.size());//预先分配内存空间
transform (numbers.begin(), numbers.end(), lengths.begin(), mem_fun(&string::length));
for (int i=0; i<5; i++) {
cout << *numbers[i] << " has " << lengths[i] << " letters.\n";
}
// deallocate strings:
for (vector<string*>::iterator it = numbers.begin(); it!=numbers.end(); ++it)
delete *it;
return 0;
}
输出:
one has 3 letters.
two has 3 letters.
three has 5 letters.
four has 4 letters.
five has 4 letters.
以上是 STL之仿函数实现详解 的全部内容, 来源链接: utcz.com/z/508885.html