C++11的函数对象、Lambda表达式、函数适配器bind()、函数类模板function<T>介绍与使用

本文详细介绍了C++中的函数对象、Lambda表达式和bind函数,探讨了它们的定义、使用方法以及如何通过bind包装类成员函数和嵌套调用。还涉及了function模板的强大功能,展示了其在不同类型函数指针上的灵活性。
摘要由CSDN通过智能技术生成

本文的内容在头文件#include <functional>

using namespace std;

using namespace std::tr1;
using namespace std::tr1::placeholders;

函数对象

函数对象是指重载了括号操作符operator()的类对象。因为可以像函数一样调用,所以称之为函数对象,其优点是既可以像函数一样调用,又可以像类一样让每个对象都拥有各自的成员变量值,而且可以作为模板参数,定义不同类型的容器。

例如:

#include <functional>
using namespace std;

//定义一个类,重载operator()
class test
{
public:
    bool operator() (int i) const
    {
        return i < 3;
    }
};


//调用
{
    test funcObj;
    funcObj(5);   //像函数调用一样使用test类的operator()
}

需要说明的是,在《C++ STL标准库-第2版》中提到,对于返回bool的判断型operator(),为了保证在传入参数不变的情况下,即使多次被调用,其返回值始终不变,所以需要声明为const.

下面列举预定义的函数对象:

Lambda表达式

Lambda表达式指的是函数定义与调用写在一起的语法,其具体的使用方法本文不做介绍,其好处在于可以共享上下文的数据,而且使用起来便捷直观。一个Lambda表达式其代表的实际上就是一个函数对象

int t = 10;
auto func = [=](int i)->int {
                return i + t;
            };

int out = func(2); //返回12

函数适配器binder

bind()返回的是一个函数对象,其operator()会对bind()第一个形参的函数调用进行包装(可多层嵌套),例如:

  • bind包装:函数对象的operator()

bind()的第一个参数传入函数对象,后面是调用的参数

#include <functional>
using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;


//定义一个类,重载operator()
class test
{
public:
    int operator() (int x, int y, int z)
    {
        return x+y+z;
    }
};

{
    test funcObj;  //定义函数对象
    auto bindFunc = bind(funcObj, std::tr1::placeholders::_2, 10, std::tr1::placeholders::_1);
    int res = bindFunc(100, 200); //返回310,即200+10+100
}

上面代码中的bindFunc就相当于一个具有以下operator()的函数对象:

int operator() (int para1, int para2)
{
    return funcObj(para2, 10,para1); //直接返回对funcObj的operator()的调用结果
}

所以,当调用bindFunc(100, 200);时,实际上就是执行:funcObj(200,10,100);,即200+10+100

  • bind包装:类成员函数

bind()的第一个参数传入成员函数,第二个参数传入的是类对象指针,后面是调用的参数

        1.用法一
class test
{
public:
    int fun1(int x, int y) 
    {
        return i + y;
    }
};

{
    test obj;
    auto bindFunc = bind(&test::fun1, &obj, std::tr1::placeholders::_1, 1314);
    int res = bindFunc(520);
}

此时代码中的bindFunc就相当于一个具有以下operator()的函数对象:

int operator() (int para1)
{
    return obj->fun1(para1, 1314);
}

所以,当调用bindFunc(520);时,实际上就是执行:obj->fun1(520, 1314);,即520+1314

        2.用法二

std::tr1::placeholders::_1、std::tr1::placeholders::_2称作占位符,我们利用占位符,还有这样玩,例如:

auto bindFunc = bind(&test::fun1, std::tr1::placeholders::_1, 666, 888);
int res = bindFunc(test());

此时代码中的bindFunc就相当于一个具有以下operator()的函数对象:

int operator() (const test& t)
{
    return t->fun1(666, 888);
}

所以,当调用bindFunc(test());时,实际上就是执行:test()的fun1(666, 888);,即666+888

这种玩法在《C++ STL标准库-第2版》中有也有提到,书上介绍了如何利用这种机制调用STL的算法函数,此处附上书上的部分内容:

bind包装:嵌套调用(可搭配STL算法函数)

 

bind包装:类的数据成员 

函数类模板function<T>

类模板function<T>是一个类模板,但我们可以将它简单理解为升级版的更加强大的函数指针。

它不但可以指向普通函数,还可以指向函数对象,正如我们上文说的,Lambda表达式、bind()返回的也是函数对象,所以只要利用bind()就能使它指向类成员函数,综上所诉,function<T>可以指向普通函数、Lambda表达式、bind()创建的对象、类成员函数,比函数指针强大多了。

function<T>的简单使用

<T>表示的是函数的调用方式,例如function<int (double, string)>,int表示的是返回值类型,(double, string)表示的是形参列表,第一个参数类型是double,第二个参数类型是string。

下面例子是function<T>指向普通函数的使用方法:

//定义一个普通函数
int testFunc(int x, string s)  
{
    return x;
}

/*定义一个调用时形参列表为(int, string)的function<T>,指向test*/
function<int (int, string)> myfunc1 = testFunc;
auto res = myfunc1(5, "good");   //返回5


/*定义一个调用时形参列表为(double, string)的function<T>,指向test*/
function<int (double, string)> myfunc2 = testFunc;
//这里实际调用的是testFunc(int x, string s)
//相当于调用了testFunc(1.1, "good"),其中,double类型的1.1会被强制转换为int类型的1
auto res = myfunc2(1.1, "good");   //返回1

function<T>与重载的函数

这里直接引用《Primer c++ -第5版》书上的内容(书上写得非常好,偷个懒~)

function<T>指向函数对象、Lambda、bind()生成的对象、类成员函数

function<int (int)> myfunc;
test obj; //定义一个函数对象obj

/***指向函数对象***/
myfunc = obj;
myfunc(520); //实际调用的是对象obj的int operator()(int)


/***指向Lambda表达式***/
myfunc = [](int x) -> int {
            retrun x;
        };
myfunc(1314);  //实际调用的是Lambda表达式的内容


/***指向bind()生成的函数对象***/
myfunc = std::tr1::bind(obj, std::tr1::placeholders::_1);
myfunc(886); //实际调用的是对象obj的int operator()(int)


/***指向类成员函数(这里使用bind做了包装,可能不是很直观,如果看不懂可以回看bind部分的介绍)***/
myfunc = bind(&test::fun1, &obj, std::tr1::placeholders::_1, 1314);
myfunc(886); //实际调用的是对象obj的成员函数int fun1(int, int),即fun1(886, 1314),返回int

哇噢~可算写完了~~

如有错误,欢迎评论指出,感谢~~

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值