C++绑定器和函数对象

C++绑定器和函数对象

简介

C++ STL中的绑定器

  • bind1st:operator()的第一个形参变量绑定一个确定的值。
  • bind2nd:operator()的第二个形参变量绑定一个确定的值。

C++ Boost库

C++的Boost库中引入了bind绑定器和function函数对象机制。

lambda表达式

lambda表达式由底层依赖函数对象的机制实现。

C++ STL中的绑定器

初识band1st和band2nd

band1st和band2nd本身还是一个函数对象。

将STL中内置的二元函数对象转化为一元函数对象使用。

#include<iostream>
#include<functional>
#include<vector>
#include<algorithm>
#include<time.h>

using namespace std;

template<typename Container>
void showContainer(Container &con){
    
    
    //由于编译的原因,所以需要加上typename,防止无法识别Container类型
    typename Container::iterator it = con.begin();
    for (; it != con.end();it++)
    {
    
    
        cout << *it << " ";
    }
    cout << endl;
}

int main(){
    
    
    vector<int> vec;
    srand(time(nullptr));
    for (int i = 0; i < 20;i++)
    {
    
    
        //产生1~100之间的随机数
        vec.push_back(rand() % 100 + 1);
    }

    showContainer(vec);
    sort(vec.begin(), vec.end());
    showContainer(vec);

    // greater二元函数对象,用于从大到小排序
    sort(vec.begin(), vec.end(), greater<int>());
    showContainer(vec);

    // bind1st和bind2nd可以将二元函数对象转化为一元函数对象,也就是说传入的默认值对应二元函数对象的形参
    // 寻找第一个小于70的索引,原序列按照从大到小排序 return 70>*it 
    // auto it = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70));
    // 寻找第一个小于70的索引,原序列按照从大到小排序 return *it<70
    auto it = find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));

    if(it!=vec.end())
    {
    
    
        vec.insert(it, 70);
    }
    showContainer(vec);
    return 0;
}

自己实现band1st和find_if

#include<iostream>
#include<functional>
#include<vector>
#include<algorithm>
#include<time.h>

using namespace std;

template<typename Container>
void showContainer(Container &con){
    
    
    //由于编译的原因,所以需要加上typename,防止无法识别Container类型
    typename Container::iterator it = con.begin();
    for (; it != con.end();it++)
    {
    
    
        cout << *it << " ";
    }
    cout << endl;
}
template <typename Compare, typename T>
class _mybind1st{
    
    
    public:
    _mybind1st(Compare comp,T val):
        _comp(comp),_val(val){
    
    }

    bool operator()(const T &second){
    
    
        return _comp(_val, second);
    }
    private:
        Compare _comp;
        T _val;
};

template <typename Compare, typename T>
_mybind1st<Compare, T> mybind1st(Compare comp, const T &val)
{
    
    
    return _mybind1st<Compare, T>(comp, val);
}

template<typename Iterator,typename Compare>
Iterator my_find_if(Iterator first,Iterator last,Compare comp){
    
    
    for (; first != last;first++){
    
    
        //comp.operator()(*first)
        if(comp(*first)){
    
    
            return first;
        }
    }
    return last;
}

int main(){
    
    
    vector<int> vec;
    srand(time(nullptr));
    for (int i = 0; i < 20;i++)
    {
    
    
        //产生1~100之间的随机数
        vec.push_back(rand() % 100 + 1);
    }

    showContainer(vec);
    sort(vec.begin(), vec.end());
    showContainer(vec);

    // greater二元函数对象,用于从大到小排序
    sort(vec.begin(), vec.end(), greater<int>());
    showContainer(vec);

    auto it = my_find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70));
    // auto it = my_find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));

    if(it!=vec.end())
    {
    
    
        vec.insert(it, 70);
    }
    showContainer(vec);
    return 0;
}

bind函数

C++11中的bind绑定器的返回结果还是一个函数对象。

初识bind函数

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

using namespace std;

void hello(string str)
{
    
    
    cout << str << endl;
}

int sum(int a,int b)
{
    
    
    return a + b;
}

class Test
{
    
    
    public:
    int sum(int a,int b)
    {
    
    
        return a + b;
    }
};

int main(){
    
    
    // bind是函数模板,可以自动推演模板类型参数,第一个参数是函数的指针
    bind(hello, "hello,world")(); 
    cout << bind(sum, 10, 20)() << endl;
    //bind使用函数对象的时候,必须要利用函数对象才能使用
    cout << bind(&Test::sum, Test(), 10, 20)()<<endl;

    // placeholders是占位符
    bind(hello, placeholders::_1)("hello,bind2!");
    bind(sum, placeholders::_1, placeholders::_2)(1, 3);

    function<void(string)> func1 = bind(hello, placeholders::_1);
    func1("hello,china!");
    func1("hello,shanghai!");
    return 0;
}

bind和function结合多线程使用

#include<iostream>
#include<string>
#include<thread>
#include<vector>
#include<functional>

using namespace std;

class Thread{
    
    
    public:
        Thread(function<void()> func) : _func(func){
    
    };
        thread start()
        {
    
    
            thread t(_func);
            return t;
        }
    private:
        function<void()> _func;
};

class ThreadPool
{
    
    
    public:
        ThreadPool(){
    
    };
        ~ThreadPool(){
    
    
            for (int i = 0;i<_pool.size();i++)
            {
    
    
                delete _pool[i];
            }
        };
        void startPool(int size)
        {
    
    
            for (int i = 0; i < size; i++)
            {
    
    
                _pool.push_back(new Thread(bind(&ThreadPool::runThread,this,i)));
            }
            for (int i = 0; i < size; i++)
            {
    
    
                _handler.push_back(_pool[i] -> start());
            }
            for (int i = 0; i < size;i++)
            {
    
    
                _handler[i].join();
            }
        }
    private:
        vector<Thread*> _pool;
        vector<thread> _handler;
        void runThread(int id)
        {
    
    
            cout << "call run Thread id :" << id << endl;
        }
};

int main()
{
    
    
        ThreadPool pool;
        pool.startPool(10);
        return 0;
}

代码打印结果,由于是多线程,所以打印结果是乱序的。

call run Thread id :call run Thread id :call run Thread id :2call run Thread id :5
call run Thread id :61
call run Thread id :9
call run Thread id :4

call run Thread id :8
0
call run Thread id :
call run Thread id :37

C++中的lambda表达式

函数对象的主要缺点:需要先定义函数,并初始化函数对象才能被使用。

C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。

Lambda 的语法形式如下:

[captures](params) -> return_type {
    
     body };

Lambda 主要分为五个部分,对应为:

[捕获列表] (函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}

上式lambda表达式中->可以省略。

捕获列表是 Lambda 表达式最有意思的地方,这里重点介绍下捕获列表。

捕获列表,用来说明外部变量的访问方式,外部变量访问方式说明符可以是 = 或 & ,表示函数体中用到的、定义在外面的变量在函数体中是否允许被改变。= 表示值传递,不允许改变。& 表示引用传递,允许改变。

包括下面几种形式:

1、[ ] 表示不捕获任何变量
2、[=] 表示按值传递的方法捕获父作用域的所有变量
3、[&] 表示按引用传递的方法捕获父作用域的所有变量
4、[=, &a] 表示按值传递的方法捕获父作用域的所有变量,但按引用传递的方法捕获变量a
5、[&, a] 表示按引用传递的方法捕获父作用域的所有变量,但按值传递的方法捕获变量a
6、[this] 捕获外部的指针

更多lambda表达式的介绍可以参考C++ 之 Lambda 表达式

mutable在lambda表达式返回类型前加上,可以在以值传递的形式上修改以值传递的变量值。

C++中的函数对象

function的作用在于:绑定器、函数对象、lambda表达式,它们只能使用在一条语句中。

初识function

#include<iostream>
#include<string>
#include<algorithm>
#include<functional>
#include<ctime>

using namespace std;

void hello1()
{
    
    
    cout << "hello,world!" << endl;
}
void hello2(string str)
{
    
    
    cout << str << endl;
}
int sum(int a,int b){
    
    
    return a + b;
}

class Test{
    
    
    public:
    void hello(string str){
    
    
        cout << str;
    }
};

int main(){
    
    

    /* 
    function函数的使用方法,function<typename(typename1,...)> xxx=yyy;
    typename表示函数的返回类型,typename_1表示寒暑的参数类型,xxx表示function重命名的函数,yyy表示原来的函数
    */
    //  调用函数hello1(),function使用的是函数类型
    function<void()> func1 = hello1;
    // 调用函数hello1(),function使用的是函数指针类型
    // function<void(*)> func1 = hello1;
    // 本质上和hello1()没有区别,调用了func1对象()重载函数->hello1.operator()
    func1();

    function<void(string)> func2 = hello2;
    func2("hello2!");

    function<int(int, int)> func3 = sum;
    cout << func3(10, 20) << endl;

    function<int(int, int)> func4 = [](int a, int b)->int{
    
     return a + b; };
    cout << func4(10, 20);

    function<void(Test*, string)> func5 = &Test::hello;
    func5(&Test(), "call Test::hello!");

    return 0;
}

自定义实现function

本质上是实现一个类,利用构造函数和()操作符重载的功能是实现函数绑定。

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

using namespace std;

void hello(string str)
{
    
    
    cout << str << endl;
}

int sum(int a,int b)
{
    
    
    return a + b;
}

template<typename Fty>
class myfunction{
    
    
};

/*
template<typename R,typename A1>
class myfunction<R(A1)>
{
    public:
        //函数返回的指针参数类型
        using PFUNC = R (*)(A1);
        myfunction(PFUNC pfunc) : _pfunc(pfunc){};
        R operator()(A1 arg){
            return _pfunc(arg);
        }
    private:
    PFUNC _pfunc;
};

template <typename R, typename A1,typename A2>
class myfunction<R(A1,A2)>
{
public:
    // 函数返回的指针参数类型
    using PFUNC = R (*)(A1,A2);
    myfunction(PFUNC pfunc) : _pfunc(pfunc){};
    R operator()(A1 arg1,A2 arg2)
    {
            return _pfunc(arg1,arg2);
    }

private:
    PFUNC _pfunc;
};
*/
// ...表示可变参数类型个数,和上面两个类的功能是一样的
template <typename R, typename... A>
class myfunction<R(A...)>
{
    
    
public:
    // 函数返回类型的指针,函数的参数类型列表
    using PFUNC = R (*)(A...);
    myfunction(PFUNC pfunc) : _pfunc(pfunc){
    
    };
    R operator()(A... arg)
    {
    
    
            return _pfunc(arg...);
    }

private:
    PFUNC _pfunc;
};

int main(){
    
    
    //就是构造函数重命名了hello函数
    myfunction<void(string)> func1(hello);
    func1("hello1");

    myfunction<int(int, int)> func2(sum);
    cout << func2(2, 3) << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45041871/article/details/131882143