C++中函数对象模板function<T>、通用函数适配器std::bind和lambda

std::function和std::bind的头文件都为#include <functional>

1、function是一个模板,跟使用其他模板一样,只不过一般用来定义函数类型模板。function操作有以下形式:

(1)function<T> f;        f是用来存储可调用对象的空function

(2)function<T>f(nullptr)        显示构造一个空fucntioin

(3)function<T>f(obj)             在f中存储可调用对象obj的副本   

(4)f(args)                调用f中的对象,参数是args

上述T为函数类型,即返回类型和参数类型。

eg:std::function<int(int,int)>//定义一个返回类型为int,形参类型为int,int的函数对象。

2、bind的形式如下:

auto newCallable = bind(callable,arg_list)

newCallable为右边bind生成新的可调用对象。callable可调用的函数,arg_list为逗号分隔的callable的参数列表。当我们调用newCallable时,newCallable会调用callable,并传递给它arg_list中的参数(需要注意的是当arg_list的参数为std;:placeholders::_1,,,时,传递的参数为newCallable调用callable函数时传递的实参,而不是定义时绑定的参数)。当bind的类函数存在参数时,生成函数调用对象的方式是newCallable = std::bind(&A::func1,this,std::placeholders::_1),即先指定类函数的对象,再指定该对象的参数。

3、lambda表达式表示一个可调用的代码单元,当函数体较少时,可定义lambda表达式。形式如下:

[capture list](parameter list)->return type{function body}

(1)capture list为lambda表达式所在上下文环境中变量的捕获,可以捕获当个变量[var1],也可以捕获整个变量[this];捕获的值用于{}函数体语句中的变量访问(例如算式运算、访问)。捕获列表方式有三种:值捕获[var1]、引用捕获[&var1]、值与引用捕获混合使用eg: [&,identifier_list]。

当然也可不用捕获lambda表达式所在上下文变量,即[]。注意书写时,捕获列表符号“[]”不能省略!!!

(2)(parameter list)->return type{function body}与其他的普通函数一样,但是lambda必须使用尾置返回类型。

(parameter list)的函数形参为空时,可以省略!!!

return type函数返回类型可以推断时,可以省略!!!

eg:

std::vector<int>vec(1,3,23,43);
std::transform(vec.begin(),vec.end(),vec.begin(),
    [](int i){return i <0 ? -i :i});

 transform函数接受三个迭代器和一个可调用对象,此例的可调用对象为lambda表达式。前两个迭代器表示输入序列,第三个迭代器表示目的位置。算法对输入序列中每个元素调用lambda表达式,并将结果写到目的迭代器位置。lambda表达式形参i的实参为调用它对象的容器中每个元素。

{function body}函数体{}不能省略!!!

demo如下:

#include <iostream>
#include <string>
#include <functional>

int call_exefunc(int a,int b)
{
    std::cout << a - b << std::endl;
    return 0;
}

using funType1 = std::function<int(int,int)>;

void call_func(funType1 pf)
{
    pf(2,3);
}

class DataCheck
{
    public:
        void printF(){std::cout << "hello DataCheck " << std::endl;}
};

class SaleItem
{
    public:
        //1 如果有多个构造函数时,仍需要编译器默认的构造函数,则可以在声明时,在()后面加default,表示使用系统生成的默认构造函数。
        //1 这种在声明时,写=default,表示构造函数为类的内联函数;如果不想用内联函数,在声明和定义分开写。
        //1 默认的构造函数的形参为空。
        SaleItem()=default;

        //2 拷贝构造函数用于类类型对象的初始化操作。如果不定义会默认生成。

        SaleItem(const SaleItem&);
    
    void PrintMem(){std::cout << "m_n1 " << m_n1 << std::endl;std::cout << "m_n2 " << m_n2 << std::endl;}
    void PrintMemPara(int val){std::cout <<" val " << std::endl;}
    int m_n1=10;
    int m_n2 = 1;;

};
SaleItem::SaleItem(const SaleItem& org)
{
    m_n1 = org.m_n1+2;
    m_n2 = org.m_n2 *2;
}

int main(int argc,char** argv)
{
    //回调函数与using and std::function的函数模板类型对象
    std::cout << "exe name is " << argv[0] << std::endl;
    call_func(call_exefunc);

    std::function<int()> fun1 = []{return 3;};
    std::cout << "fun1 " << fun1() << std::endl;

    std::function<int(int,int)> fun2 = call_exefunc;
    std::cout << fun2(3,1) << std::endl;

    std::function<int(int,int)> fun3 = std::bind(call_exefunc,std::placeholders::_1,std::placeholders::_2);
    std::cout << fun3(3,1) << std::endl;

    //std::bind在绑定普通函数时跟其他的普通函数的函数指针方法一致,std::bind可以绑定类成员函数,这个是普通函数代替不了的。
    DataCheck objData;
    std::function<void()>fun4 = std::bind(&DataCheck::printF,&objData);
    fun4();

    SaleItem objSale;
    std::function<void()> fun5 = std::bind(&SaleItem::PrintMem,&objSale);
    fun5();

    SaleItem objSale2;
    std::function<void()> fun6 = std::bind(&SaleItem::PrintMemPara,&objSale2,std::placeholders::_1);
    fun6(1);

    SaleItem obj1;
    SaleItem obj2(obj1);    //拷贝构造函---将类对象作为另一个函数的形参
    obj2.PrintMem();
    SaleItem obj3 = obj1;   //拷贝构造函----使用=
    obj3.PrintMem();

    return 0;
}

附加知识:

【C++】C++11的std::function和std::bind用法详解_c++ bind 对象成员函数到普通函数_Yngz_Miao的博客-CSDN博客

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值