C++11的std::function和bind绑定器

这篇具有很好参考价值的文章主要介绍了C++11的std::function和bind绑定器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

可调用对象

        在C++中,存在“可调用对象”这么一个概念。准确来说,可调用对象有如下几种定义:

                1、是一个函数指针

                2、是一个具有operator()成员函数的类对象(仿函数)

                3、是一个可转换为函数指针的类对象

                4、是一个类成员(函数)指针

#include <iostream>
using namespace std;

void func(void)
{}

struct Foo
{
    void operator()(void){}
};

struct Bar
{
    using fr_t = void(*)(void);

    static void func(void)
    {
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
    }

    operator fr_t(void)
    {
        return func;
    }
};

struct A
{
    int a_;

    void mem_func(void)
    {
        printf("%s %s %d\n", __FILE__, __func__, __LINE__);
    }
};

int main()
{
    void (*func_ptr)(void) = &func; ///1、函数指针
    func_ptr();

    Foo foo;
    foo();                          ///2、仿函数

    Bar bar;
    bar();                          ///3、可被转化为函数指针的类对象

    void (A::*mem_func_ptr)(void) = &A::mem_func;   ///4、类成员函数指针

    int A::*mem_obj_ptr = &A::a_;           ///类成员指针

    A aa;
    (aa.*mem_func_ptr)();
    aa.*mem_obj_ptr = 123;

    return 0;
}

        从上述可以看到,除了类成员指针之外,上面定义涉及的对象均为可以像一个函数那样做调用操作。

        在C++11中,像上面例子中的这些对象(func_ptr,foo,bar,mem_func_ptr,mem_obj_ptr)都被称为可调用对象。相对应的,这些对象的类型被统称为“可调用类型”。

        现在,C++11通过std::function和std::bind统一了可调用对象的各自操作。

可调用对象包装器---std::function

        std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执行它们。

std::function的基本用法

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

void func(void)
{
    cout << __FUNCTION__ << endl;
}

class Foo
{
public:
    static int foo_func(int a)
    {
        cout << __FUNCTION__ << "(" << a << ") ->: ";
        return a;
    }
};

class Bar
{
public:
    int operator()(int a)
    {
        cout << __FUNCTION__ << "(" << a << ") ->: ";
        return a;
    }

};

int main()
{
    function<void(void)> fr1 = func;        ///绑定一个普通函数
    fr1();

    ///绑定一个类的静态成员函数
    std::function<int(int)> fr2 = Foo::foo_func;
    cout << fr2(123) << endl;

    Bar bar;
    fr2 = bar;
    cout << fr2(123) << endl;

    return 0;
}

运行结果如下:

C++11的std::function和bind绑定器,C++11,c++,开发语言

        从上面我们可以看到std::function的使用方法,当我们给std::function填入合适的函数签名(即一个函数类型,只需要包括返回值和参数表)之后,它就变成了一个可以容纳所有这一类调用方式的“函数包装器”。

std::function作为回调函数的示例

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

class A
{
public:
    A(const std::function<void()> & f):callback_(f){}

    void notify(void)
    {
        callback_();
    }

private:
    std::function<void()> callback_;
};

class Foo
{
public:
    void operator()(void)
    {
        cout << __FUNCTION__ << endl;
    }
};

int main()
{
    Foo foo;
    A aa(foo);

    aa.notify();

    return 0;
}

        从上面的例子中可以看到,std::function可以取代函数指针的作用。因为它可以保存函数延迟执行,所以比较适合作为回调函数。

std::function作为函数入参示例

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

void call_when_even(int x, const std::function<void(int)>& f)
{
    if (!(x & 1))
    {
        f(x);
    }
}

void output(int x)
{
    cout << x << " ";
}

int main()
{
    for(int i = 0; i < 10; i++)
    {
        call_when_even(i, output);
    }
    cout << endl;

    return 0;
}

        从上面的例子中可以看到,std::function比普通函数指针更灵活和便利。

std::bind绑定器

        std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。

        通俗来讲,它主要有两大作用:

        1、将可调用对象与其参数一起绑定成一个仿函数。

        2、将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。

std::bind基本用法

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

void call_when_even(int x, const std::function<void(int)>& f)
{
    if (!(x & 1))
    {
        f(x);
    }
}

void output(int x)
{
    cout << x << " ";
}

void output_add_2(int x)
{
    cout << x + 2 << " ";
}


int main()
{
    {
        auto fr = std::bind(output, std::placeholders::_1);
        for(int i = 0; i < 10; i++)
        {
            call_when_even(i, fr);
        }
        cout << endl;
    }

    {
        auto fr = std::bind(output_add_2, std::placeholders::_1);
        for(int i = 0; i < 10; i++)
        {
            call_when_even(i, fr);
        }
        cout << endl;
    }

    return 0;
}

        我们使用std::bind在函数外部通过绑定不同的函数,控制了最后的执行结果。

        我们使用auto fr保存std::bind的返回结果,因为我们不关心std::bind真正的返回类型(实际上std::bind的返回类型是一个stl内部定义的仿函数类型),只需要知道它是一个仿函数,可以直接赋值给一个std::function。当然,这里直接使用std::function类型来保存std::bind的返回值也是可以的。

        std::placeholders::_1是一个占位符,代表这个位置将在函数调用时,被传入的第一个参数所替代。

std::bind的占位符

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

void output(int x, int y)
{
    cout <<  x << " " << y << endl;
}

int main()
{
    ///输出1,2
    std::bind(output, 1, 2)();

    ///输出2,2
    std::bind(output, std::placeholders::_1, 2)(2);

    ///输出3,444
    std::bind(output, 3, std::placeholders::_1)(444);

    ///error,调用时没有第二个参数
    ///std::bind(output, 3, std::placeholders::_2)(333);

    ///调用时第一个参数被吞掉了
    ///输入1, 333
    std::bind(output, 1, std::placeholders::_2)(7, 333);

    ///输入7, 333
    std::bind(output, std::placeholders::_1, std::placeholders::_2)(7, 333);

    return 0;
}

        上面对std::bind的返回结果直接施以调用。可以看到,std::bind可以直接绑定函数的所有参数,也可以绑定部分参数。

        在绑定部分参数的时候,通过std::placeholders,来决定空位参数将会属于调用发生时的第几个参数。

std::bind和std::function配合使用

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

class A
{
public:
    int i_ = 0;

    void output(int x, int y)
    {
        cout << x << " " << y << endl;
    }
};

int main()
{
    A a;

    std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1, std::placeholders::_2);

    fr(1, 2);

    std::function<int& (void)> fr_i = std::bind(&A::i_, &a);

    fr_i() = 123;

    cout << a.i_ << endl;

    return 0;
}

        fr的类型是std::function<void(int, int)>。我们通过使用std::bind,将A的成员函数output的指针和a绑定,并转换为一个仿函数放入fr中存储。

        之后,std::bind将A的成员i_的指针和a绑定,返回的结果被放入std::function<int&(void)>中存储,并可以在需要时修改访问这个成员。文章来源地址https://www.toymoban.com/news/detail-718673.html

到了这里,关于C++11的std::function和bind绑定器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c++ | this指针 和bind、function

    个人理解: this 指针 可以简单理解为类 对象的 指针(也是隐藏指针),注意,类的成员(成员函数、成员变量)是通过类的对象进行调用的。如果把函数充当成员函数是错误的,粗鲁的解释,类的成员函数都有一个隐藏的指针(this指针),但是 c函数是没有指针的。 看看

    2024年02月13日
    浏览(37)
  • 使用std::function 来实现回调函数、委托的功能

    std::function 可以用来实现回调函数和委托的功能。下面是一个回调函数的示例: 在上述示例中,我们定义了回调函数 printText ,这个函数接受一个字符型指针参数,并打印出这个字符串。然后,我们定义了函数 processText ,该函数接受两个参数:文本和一个 std::function 类型的对

    2024年02月09日
    浏览(42)
  • 【C++】STL 算法 ⑩ ( 函数适配器 | 函数适配器概念 | 函数适配器分类 | 函数适配器辅助函数 | std::bind2nd 函数原型及示例 | std::bind 函数原型及示例 )

    在 STL 中 预定义了很多 函数对象 , 如果要 对 函数对象 的 参数 / 返回值 进行 计算 或 设置 , 可以 使用 \\\" 函数适配器 \\\" 实现上述需求 ; \\\" 函数适配器 \\\" 可以 将 已存在的 函数对象 转化为 另一种符合要求的 函数对象 ; \\\" 函数适配器 \\\" 定义在 functional 头文件 中 ; \\\" 函数适配器

    2024年02月02日
    浏览(65)
  • 【JavaScript】手撕前端面试题:手写Object.create | 手写Function.call | 手写Function.bind

    🖥️ NodeJS专栏:Node.js从入门到精通 🖥️ 博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述) 🖥️ TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结) 🧑‍💼个人简介:大三学生,一个不甘平庸的平凡人🍬 👉

    2024年02月21日
    浏览(78)
  • 10.9.2 std::function 代替函数指针 Page182~183

    std::function是一个模板类,基本可作为函数指针的代替品,具备更多功能,特别是与函数对象及bind配合使用。使用std::function时,需要添加头文件 #include functional 18行,定义了一个函数指针类型PFoo, 19行,声明一个函数指针pfoo,并将foo赋给pfoo 37行,定义了一个function类型,该类

    2024年01月20日
    浏览(33)
  • iOS报错命名空间“std”中的“unary_function”

    刚刚将我的 Xcode 升级到 15.0,突然它开始在 RCT_Folly 中出现以下错误 我尝试删除缓存数据和派生数据并清理构建。也尝试删除 pod 和 node_modules。但没有任何帮助。 于是我按照网上提供的方法解决了: 选择 Pods 构建设置 在“Apple Clang - 预处理”部分 在“宏”部分下 添加发布和

    2024年02月05日
    浏览(46)
  • [开发语言][c++]:左值、右值、左值引用、右值引用和std::move()

    写在前面: 如果你也被 左值、右值、左值引用、右值引用和std::move 搞得焦头烂额,相关概念和理解不够深入,或者认识模棱两可,那么这篇文章将非常的适合你,耐心阅读,相信一定会有所收获~~ 左值: 可以取地址、位于等号左边 – 表达式结束后依然存在的持久对象

    2024年02月02日
    浏览(62)
  • C++笔记之从使用函数指针和typedef到使用std::function和using

    参考笔记:C++笔记之从数组指针到函数数组指针(使用using name和std::function) code review!

    2024年02月15日
    浏览(44)
  • 【C++11】 包装器 | bind

    function包装器 也被叫做 适配器 C++11中function本质是 类模板, 也是一个包装器 意义在于 对可调用对象类型进行封装再适配 可调用对象:函数指针 / lambda / 仿函数 需要包含 头文件 functional 模板参数 Ret : 被调用函数的返回类型 …Args作为参数包,这个参数包中包含0到任意个模

    2024年02月12日
    浏览(41)
  • C++ 11新特性之bind

    概述         std::bind是C++ 11中functional头文件提供的一个函数模板,它允许我们将函数或成员函数与其部分参数预先绑定在一起,形成一个新的可调用对象(英文为:Callable Object)。这个新的可调用对象可以在后续时机以剩余参数完成调用,这个机制对于事件处理、回调函

    2024年02月21日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包