c++高阶语法(五)

今天,我们来看看c++11中的一个可调用对象包装器——function以及在头文件<functional>下的bind函数。

一.functional

1.概念:

std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执行它们。包装器function使其能够存储、复制、调用任何可复制构造的可调用对象1,包括全局函数、成员函数、函数对象、lambda表达式、bind表达式。

2.基本用法:

std::function必须要包含一个叫做functional的头文件,可调用对象包装器使用语法如下:

#include <functional>

std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;

主要以下包装用途:

1.包装普通函数

2.包装类的静态函数

3.包装仿函数

4.包装转换成函数指针的对象

从下面例子中体会这四种用途吧

例子一:

#include <iostream>
#include <functional>
#include <string>
using namespace std;

void print(int num, string name)
{
    cout << "id = "<<name << ",age = " << num << endl;
}

using funcptr = void(*)(int, string);

class Test
{
public:
    static void world(int a, string s)
    {
        cout << "number = " << a << ",name = " << s << endl;
    }

    void operator()(string msg)
    {
        cout << "仿函数:" << msg << endl;
    }

    operator funcptr()
    {
        return world;
    }
};


int main()
{
    //1.包装普通函数
    function<void(int, string)> f1 = print;
    //2.包装类的静态方法
    function<void(int, string)> f2 = Test::world;
    //3.包装仿函数
    Test ta;
    function<void(string)> f3 = ta;
    //4.包装转换成函数指针的对象
    Test tb;
    function<void(int, string)> f4 = tb;

    //调用
    f1(1, "ace");
    f2(2, "tom");
    f3("jack");
    f4(3, "lily");
    return 0;
}

例子二:

#include <iostream>
#include <functional>
#include <string>
using namespace std;

class A
{
public:
    A(const function<void(int, string)> &f) :callback(f)
    {

    }

    void notify(int id, string name)
    {
        callback(id, name);
    }
private:
    function<void(int, string)> callback;
};

void print(int num, string name)
{
    cout << "id = " << name << ",age = " << num << endl;
}

using funcptr = void(*)(int, string);

class Test
{
public:
    static void world(int a, string s)
    {
        cout << "number = " << a << ",name = " << s << endl;
    }

    void operator()(string msg)
    {
        cout << "仿函数:" << msg << endl;
    }

    operator funcptr()
    {
        return world;
    }
};


int main()
{
    //1.包装普通函数
    function<void(int, string)> f1 = print;
    //2.包装类的静态方法
    function<void(int, string)> f2 = Test::world;
    //3.包装仿函数
    Test ta;
    function<void(string)> f3 = ta;
    //4.包装转换成函数指针的对象
    Test tb;
    function<void(int, string)> f4 = tb;

    A aa(print);
    aa.notify(1, "tom");

    A ab(Test::world);
    ab.notify(2, "jack");

    A ac(tb);
    ac.notify(3, "luf");
    return 0;
}

二.bind
概念:bind是一个标准库函数,定义在functional头文件中。可以将bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成新的可调用对象来适应原对象的参数列表。

调用bind的一般形式为:auto newCallable=bind(callable,arg_list)

newCallable和callable都是可调用对象,arg_list对应calllable的参数。当我们调用newCallable时,newCallable会调用callable,并传递给它arg_list中的参数
arg_list中的参数可能包含形如_n的占位符,如_1,_2,代表了newCallable中相应位置的参数

auto check6=bind(check_size,_1,6);当我们调用check6(str)的时候,实际会调用check_size(str,6)

bind作用:

1.改变参数个数:bind可以用于改变参数的个数(减少?),如原本check_size要传入两个参数,通过bind我们可以只传入一个参数,另外的参数则在bind时决定。

2.改变参数位置:bind还可用于改变参数位置,例如,有一个函数bool isGreater(int a,int b)用于判断第一个参数是否大于第二个参数,则auto isSmaller=bind(isGreater,_2,_1);

通过改变参数顺序,让bind返回的可调用对象具有相反的含义。isSmaller(1,2)将实际调用isGreater(2,1),返回true。

3.设置类成员函数为回调函数

回调函数往往通过函数指针来实现,而类的成员函数,多了一个隐含的参数this,所以直接赋值给函数指针会引起编译报错。通过bind可以解决此问题

class MyClass
{
public:
    MyClass() :n(0) {};
    ~MyClass()=default;
    void add(int i) { n += i; cout << n; }

private:
    int n;
};
MyClass a;
auto f=bind(&test::incr,&a,_1);
MyClass a;
auto f = bind(&MyClass::add, &a, _1);
f(1);//输出1
f(2);//输出 3

4.bind绑定引用参数

默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中,但有些参数无法拷贝,可以使用标准库中的ref函数,它返回给定参数的引用。

ostream& print(ostream& os, const string& s, char c)
{
    return os << s << c;
}
print(cout, "123", '-');//打印123-
//
vector<string> strVec = {"abc","def"};
//for_each(strVec.begin(), strVec.end(), bind(print,cout,_1,'-'));将报错cout无法拷贝
for_each(strVec.begin(), strVec.end(), bind(print,ref(cout),_1,'-'));//输出abc-def-

这里说一下ref函数:ref可以在模板传参的时候传入引用,否则无法传递

好啦,关于function和bind就分享到这啦。

本贴为博主亲手整理。如有错误,请评论区指出,一起进步。谢谢大家的浏览.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值