• C++ std::tr1::function和std::tr1::bind模板类介绍,qt测试



    C语言使用函数指针来把一个函数作为参数传递,这样我们就可以实现回调函数的机制。到了C++11以后在标准库里引入了std::function模板类,这个模板概括了函数指针的概念。
    函数指针只能指向一个函数,而std::function函数包装器模板能包装任何类型的可调用实体,如普通函数、函数对象、lambda表达式、静态成员函数等。
    std::bind是对std::function功能的扩展,可指向类的非静态成员函数,使用参数占位符等。

    std::function声明和代码示例

    基本语法:function<函数模板类型> 包装器名
    函数模板类型无需函数名,不可省略返回值和参数列表。

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    using namespace std;
    int square(int val)//普通函数
    {
        return val * val;
    }
    
    typedef int (* FnSquare)(int);//函数指针
    
    class FuncTmp{
    public:
        static int tmpJisuan(int num){//静态成员函数
            printf("tmpJisuan num=%d\n",num);
            return 0;
        };
        void operator()()//仿函数
        {
            printf("FuncTmp()\n");
        }
    };
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        int a = 5;
        function<int (int)> func1 = square;	//包装普通函数
        FnSquare fnSquare = square;
        function<int (int)> func2 = fnSquare;	//包装函数指针
        function<void ()> func3 = FuncTmp();	//包装仿函数(函数对象)
        function<void (int)> func4 = [](int a){	//包装Lambda表达式
            printf("a=%d\n",a);
        };
        function<void (int)> func5;//未赋值的空对象
        function<int(int)> func6 = FuncTmp::tmpJisuan;//包装静态成员函数
    
        printf("func1(a)=%d\n",func1(a));
        printf("func2(2)=%d\n",func2(2));
        func3();
        func4(10);
        //非空判断
        if(func4)
            printf("func4!=null\n");
        if(!func5)
            printf("func5==null\n");
        func6(52);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    打印

    func1(a)=25
    func2(2)=4
    FuncTmp()
    a=10
    func4!=null
    func5==null
    tmpJisuan num=52
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    std::bind声明和代码示例

    同function函数类似,bind函数同样也可以实现类似于函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类 的非静态成员函数时。
    函数模板 bind 生成 func的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用func 。

    //bind的声明
    template<class Fty, class T1, class T2, ..., class TN>
       unspecified bind(Fty fn, T1 t1, T2 t2, ..., TN tN);
    
    • 1
    • 2
    • 3

    其中Fty为调用函数所属的类,fn为将被调用的函数,t1…tN为函数的参数。如果不指明参数,则可以使用占位符表示形参,占位符格式为std::tr1::placehoders::_1, std::tr1::placehoders::_2, …

    std::bind主要用法:
    1、绑定全局函数(包括静态成员函数),传入参数,相当于直接调用了该全局函数。
    2、把实例化的对象和类的非静态成员函数绑定,返回的函数指针赋值给std::function对象,通过std::function对象调用函数指针。
    3、把实例化的对象和类的非静态成员函数绑定,如果函数有参数,可以在bind时传参。
    4、把实例化的对象和类的非静态成员函数绑定,bind时参数可以使用占位符,调用std::function对象时再传参。
    代码示例

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include 
    #include 
    #include 
    
    //声明未初始化的function函数包装器
    typedef std::tr1::function<void()> Fun;
    typedef std::tr1::function<void(int)> Fun2;
    
    int CalSum(int a, int b){
        printf("%d + %d = %d\n",a,b,a+b);
        return a+b;
    }
    class Animal{
    public:
        Animal(){}
        void Move(){}
    };
    
    class Bird: public Animal{
    public:
        Bird(){}
        void Move(){
            std::cout<<"I am flying...\n";
        }
    };
    
    class Fish: public Animal{
    public:
        Fish(){}
        void Move(){
            std::cout<<"I am swimming...\n";
        }
        void Say(int hour){
            std::cout<<"I have swimmed "<<hour<<" hours.\n";
        }
    };
    
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        std::tr1::bind(&CalSum,3,4)();//1.全局函数直接使用函数地址,相当于调用了CalSum
    
        Bird bird;
        Fun fun = std::tr1::bind(&Bird::Move,&bird);//2.把实例化的对象和成员函数绑定,函数指针赋值给function
        fun();
    
        Fish fish;
        fun = std::tr1::bind(&Fish::Move,&fish);//类似上一个bind
        fun();
    
        //bind style one.
        fun = std::tr1::bind(&Fish::Say,&fish,3);//3.实例化的对象和带参数成员函数绑定,参数直接传
        fun();
    
        //bind style two.
        //4.实例化的对象和带参数成员函数绑定,参数使用占位符,调用时再传参
        Fun2 fun2 = std::tr1::bind(&Fish::Say,&fish, std::tr1::placeholders::_1);
        fun2(3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    打印

    3 + 4 = 7
    I am flying...
    I am swimming...
    I have swimmed 3 hours.
    I have swimmed 3 hours.
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    C# 45. ref和out的区别
    【C++】运算符重载 ⑨ ( 等号 = 运算符重载 | 调用默认浅拷贝构造函数的情况分析 | 等号 = 运算符重载 与 拷贝构造函数 各自使用场景 | 等号 = 操作符重载步骤 )
    异常检测:Towards Total Recall in Industrial Anomaly Detection
    主谓一致基本语法
    有趣的小实验:如何在MacOS12上测试iOS16和MacOS13系统中才有的新Clock对象
    leetcode_1402 做菜顺序
    【MySQL】MySQL的安装,登录,配置和相关命令
    面向面试知识-Redis
    基于or-tools的护士排班问题建模求解
    使用百度EasyDL实现银行客户流失预测
  • 原文地址:https://blog.csdn.net/weixin_40355471/article/details/128158139