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函数时传递的实参,而不是定义时绑定的参数)。

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

    return 0;
}

猜你喜欢

转载自blog.csdn.net/hanxiaoyong_/article/details/128772254