C++ 学习系列 -- std::function 与 std::bind

一  std::function  与 std::bind 的介绍

     1. std::function  

     std::function 是 c++ 11 的新特性 ,包含在头文件<functional>中,为了更方便的调用函数而引入。

       std::function 是一个函数包装器(function wrapper),可以包装任何可调用实体,包括如下几种:

       普通函数、函数指针、成员函数、静态函数、lambda 表达式 与 仿函数对象。

     std::function 对象实例可以拷贝与移动,可以使用指定的调用特征来调用目标元素。当 std::function 对象实例未包含任何实体时,调用该 std::function 对象实例时,会抛出std::bad_function_call异常。

    2. std::bind

      std::bind 是 c++ 11 的新特性,其作用与其字面名称相似,是为了绑定函数的某些参数。

std::bind 是一种延迟计算的思想,将可调用函数对象保存起来,在需要调用时再去调用。可以绑定

仿函数对象、普通函数与成员函数,其参数可以支持占位符。

占位符:

       std::placeholders::_1 是一个占位符,绑定函数的第一个参数,std::placeholders::_2 是一个占位符,绑定函数的第二个参数,std::placeholders::_n 是一个占位符,绑定函数的第 n 个参数。

二   源码 

2.1    std::function

template<typename _Signature>
    class function;

  /**
   *  @brief Primary class template for std::function.
   *  @ingroup functors
   *
   *  Polymorphic function wrapper.
   */
  template<typename _Res, typename... _ArgTypes>
    class function<_Res(_ArgTypes...)>
    : public _Maybe_unary_or_binary_function<_Res, _ArgTypes...>,
      private _Function_base
    {
      template<typename _Func,
	       typename _Res2 = typename result_of<_Func&(_ArgTypes...)>::type>
	struct _Callable : __check_func_return_type<_Res2, _Res> { };

      // Used so the return type convertibility checks aren't done when
      // performing overload resolution for copy construction/assignment.
      template<typename _Tp>
	struct _Callable<function, _Tp> : false_type { };

      template<typename _Cond, typename _Tp>
	using _Requires = typename enable_if<_Cond::value, _Tp>::type;

    public:
      typedef _Res result_type;

      // [3.7.2.1] construct/copy/destroy

      /**
       *  @brief Default construct creates an empty function call wrapper.
       *  @post @c !(bool)*this
       */
      function() noexcept
      : _Function_base() { }

      /**
       *  @brief Creates an empty function call wrapper.
       *  @post @c !(bool)*this
       */
      function(nullptr_t) noexcept
      : _Function_base() { }

      /**
       *  @brief %Function copy constructor.
       *  @param __x A %function object with identical call signature.
       *  @post @c bool(*this) == bool(__x)
       *
       *  The newly-created %function contains a copy of the target of @a
       *  __x (if it has one).
       */
      function(const function& __x);

      /**
       *  @brief %Function move constructor.
       *  @param __x A %function object rvalue with identical call signature.
       *
       *  The newly-created %function contains the target of @a __x
       *  (if it has one).
       */
      function(function&& __x) noexcept : _Function_base()
      {
	       __x.swap(*this);
      }

      /**
       *  @brief Builds a %function that targets a copy of the incoming
       *  function object.
       *  @param __f A %function object that is callable with parameters of
       *  type @c T1, @c T2, ..., @c TN and returns a value convertible
       *  to @c Res.
       *
       *  The newly-created %function object will target a copy of
       *  @a __f. If @a __f is @c reference_wrapper<F>, then this function
       *  object will contain a reference to the function object @c
       *  __f.get(). If @a __f is a NULL function pointer or NULL
       *  pointer-to-member, the newly-created object will be empty.
       *
       *  If @a __f is a non-NULL function pointer or an object of type @c
       *  reference_wrapper<F>, this function will not throw.
       */
      template<typename _Functor,
	       typename = _Requires<__not_<is_same<_Functor, function>>, void>,
	       typename = _Requires<_Callable<_Functor>, void>>
	function(_Functor);

      /**
       *  @brief %Function assignment operator.
       *  @param __x A %function with identical call signature.
       *  @post @c (bool)*this == (bool)x
       *  @returns @c *this
       *
       *  The target of @a __x is copied to @c *this. If @a __x has no
       *  target, then @c *this will be empty.
       *
       *  If @a __x targets a function pointer or a reference to a function
       *  object, then this operation will not throw an %exception.
       */
      function&
      operator=(const function& __x)
      {
	    function(__x).swap(*this);
	    return *this;
      }

      /**
       *  @brief %Function move-assignment operator.
       *  @param __x A %function rvalue with identical call signature.
       *  @returns @c *this
       *
       *  The target of @a __x is moved to @c *this. If @a __x has no
       *  target, then @c *this will be empty.
       *
       *  If @a __x targets a function pointer or a reference to a function
       *  object, then this operation will not throw an %exception.
       */
      function&
      operator=(function&& __x) noexcept
      {
	    function(std::move(__x)).swap(*this);
	    return *this;
      }
     
      template<typename _Functor>
	_Requires<_Callable<typename decay<_Functor>::type>, function&>
	operator=(_Functor&& __f)
	{
	  function(std::forward<_Functor>(__f)).swap(*this);
	  return *this;
	}

      /// @overload
      template<typename _Functor>
	function&
	operator=(reference_wrapper<_Functor> __f) noexcept
	{
	  function(__f).swap(*this);
	  return *this;
	}

      /**
       *  @brief Invokes the function targeted by @c *this.
       *  @returns the result of the target.
       *  @throws bad_function_call when @c !(bool)*this
       *
       *  The function call operator invokes the target function object
       *  stored by @c this.
       */
      _Res operator()(_ArgTypes... __args) const;
  };

2.2    std::bind

// Trait type used to remove std::bind() from overload set via SFINAE
  // when first argument has integer type, so that std::bind() will
  // not be a better match than ::bind() from the BSD Sockets API.
  template<typename _Tp, typename _Tp2 = typename decay<_Tp>::type>
    using __is_socketlike = __or_<is_integral<_Tp2>, is_enum<_Tp2>>;

  template<bool _SocketLike, typename _Func, typename... _BoundArgs>
    struct _Bind_helper
    : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>
    {
      typedef typename decay<_Func>::type __func_type;
      typedef _Bind<__func_type(typename decay<_BoundArgs>::type...)> type;
    };

  // Partial specialization for is_socketlike == true, does not define
  // nested type so std::bind() will not participate in overload resolution
  // when the first argument might be a socket file descriptor.
  template<typename _Func, typename... _BoundArgs>
    struct _Bind_helper<true, _Func, _BoundArgs...>
    { };

  /**
   *  @brief Function template for std::bind.
   *  @ingroup binders
   */
  template<typename _Func, typename... _BoundArgs>
    inline typename
    _Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type
    bind(_Func&& __f, _BoundArgs&&... __args)
    {
      typedef _Bind_helper<false, _Func, _BoundArgs...> __helper_type;
      return typename __helper_type::type(std::forward<_Func>(__f),
					  std::forward<_BoundArgs>(__args)...);
    }

  template<typename _Result, typename _Func, typename... _BoundArgs>
    struct _Bindres_helper
    : _Bind_check_arity<typename decay<_Func>::type, _BoundArgs...>
    {
      typedef typename decay<_Func>::type __functor_type;
      typedef _Bind_result<_Result,
			   __functor_type(typename decay<_BoundArgs>::type...)>
	type;
    };

  /**
   *  @brief Function template for std::bind<R>.
   *  @ingroup binders
   */
  template<typename _Result, typename _Func, typename... _BoundArgs>
    inline
    typename _Bindres_helper<_Result, _Func, _BoundArgs...>::type
    bind(_Func&& __f, _BoundArgs&&... __args)
    {
      typedef _Bindres_helper<_Result, _Func, _BoundArgs...> __helper_type;
      return typename __helper_type::type(std::forward<_Func>(__f),
					  std::forward<_BoundArgs>(__args)...);
    }

三   使用例子

 

#include<iostream>
#include<functional>

int (*func_ptr)(int);

int func(int a)
{
    std::cout << "func: " << a << endl;
    return a;
}

void f(int n1, int n2, int n3, const int& n4, int n5) {
    std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << std::endl;
}

template<typename T>
T fun2(T a){
    return a + 2;
}

struct my_add{
    int operator()(int x){
        return x + 9;
    }
};

struct Foo
{
    static void func11()
    {
        std::cout << "static void func1......" << std::endl;
    }
    static void func12(int val)
    {
        std::cout << "static void func1( val "<< val << "......" << std::endl;
    }

    void func2(int val)
    {
        std::cout << "void func2(val "<< val << ")......" << std::endl;
    }

};

int main()
{
     // 1. 包装函数
     std::function<int(int)>  f1 = func;
     f1(66);
     std::cout << sizeof (f1) << std::endl;

     // 2. 包装函数指针
     func_ptr = func;
     func_ptr(88);

     // 3. 包装模板函数
     f1 = fun2<int>;
     f1(688);

     // 4. 包装仿函数
     f1 = my_add();
     std::cout << f1(87) << std::endl;

     // 5. 包装lambda 函数
     auto tmp_func = [](int a)->int
     {
           return a;
     };

     f1 = tmp_func;
     std::cout << f1(8888) << std::endl;


     // 6 包装静态函数
     std::function<void(void)> f61 = Foo::func11;
     f61();

     std::function<void(int)>  f62 = Foo::func12;
     f62(666);


     // 7 包装类成员函数
     Foo foo;
     std::function<void(int)> f7 = std::bind(&Foo::func2, foo, std::placeholders::_1);
     f7(888);


     // bind
     auto f2 = std::bind(f, std::placeholders::_3, std::placeholders::_2, std::placeholders::_1, 4, 5);
     f2(3, 2, 1);
     std::function<void(int, int, int)> ff = f2;
     ff(3, 2, 1);
     std::cout << "------ main end ------" << std::endl;

     return 0;
}

输出:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/336485.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Cmake(1)——Cmake的基本介绍和原理、Cmake的安装、如何使用Cmake构建项目

Cmake的基本介绍和原理、Cmake的安装、如何使用Cmake构建项目 插播&#xff01;插播&#xff01;插播&#xff01;亲爱的朋友们&#xff0c;我们的Cmake课程上线啦&#xff01;感兴趣的小伙伴可以去下面的链接学习哦~ https://edu.csdn.net/course/detail/39261 1、Cmake的基…

在微信公众号中加入ChatGPT聊天的方法

1 介绍 开源项目 "chatgpt-on-wechat" 支持通过微信公众号进行调用&#xff0c;这意味着用户可以在与公众号的交互中体验 ChatGPT。由于服务是部署在远端服务器上的&#xff0c;因此用户只需拥有一部手机&#xff0c;就可以在任何环境下与 ChatGPT 进行交流。例如&am…

fabric.js 组件 图片上传裁剪并进行自定义区域标记

目录 0. 前言 1. 安装fabric与引入 2. fabric组件的使用 3. 属性相关设置 4. 初始化加载 4. 方法 5. 全代码 0. 前言 利用fabric组件&#xff0c;实现图片上传、图片”裁剪“、自定义的区域标记一系列操作 先放一张效果图吧&#x1f447; 1. 安装fabric与引入 npm i …

Flink(十三)【Flink SQL(上)SqlClient、DDL、查询】

前言 最近在假期实训&#xff0c;但是实在水的不行&#xff0c;三天要学完SSM&#xff0c;实在一言难尽&#xff0c;浪费那时间干什么呢。SSM 之前学了一半&#xff0c;等后面忙完了&#xff0c;再去好好重学一遍&#xff0c;毕竟这玩意真是面试必会的东西。 今天开始学习 Flin…

“GPC爬虫池有用吗?

作为光算科技的独有技术&#xff0c;在深入研究谷歌爬虫推出的一种吸引谷歌爬虫的手段 要知道GPC爬虫池是否有用&#xff0c;就要知道谷歌爬虫这一概念&#xff0c;谷歌作为一个搜索引擎&#xff0c;里面有成百上千亿个网站&#xff0c;对于里面的网站内容&#xff0c;自然不可…

虚拟机安装宝塔的坑

问题&#xff1a; 在虚拟机中centos7和centos8中安装宝塔之后&#xff0c;无法访问面板。 解决&#xff1a; 1.先关闭防火墙&#xff08;如果本机能够ping通相关端口&#xff0c;则不用关闭防火墙&#xff09; 2.最新的宝塔会自动开启ssl协议&#xff0c;需要手动关闭。…

PostgreSQL 是不是大小写敏感

如果你踩过 MySQL 的大坑的话就知道&#xff1a;MySQL 在 Windows 下不区分大小写&#xff0c;但在 Linux 下默认是区分大小写。 如果你稍加不注意就会出现在本机开发的程序运行一切正常&#xff0c;发布到服务器行就出现表名找不到的问题。 这是我们前一个项目遇到的巨大问题…

【力扣4行代码解题】572另一棵树的子树 | C++

总结&#xff1a;本题可以使用递归和迭代法&#xff0c;但平时还是建议两种方法都掌握&#xff0c;感兴趣的同学可以看看原题。 文章目录 1 题目2 知识点3 代码及解释 1 题目 力扣链接 > 572.另一棵树的子树 给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 sub…

探索图像检索:从理论到实战的应用

目录 一、引言二、图像检索技术概述图像检索的基本概念图像检索与文本检索的区别特征提取技术相似度计算索引技术 三、图像检索技术代码示例图像特征提取示例相似度计算索引技术 四、图像搜索流程架构数据采集与预处理特征提取相似度计算与排名结果呈现与优化 五、实际应用图像…

基于Java+SSM志愿者服务管理系统详细设计和实现【附源码】

基于JavaSSM志愿者服务管理系统详细设计和实现【附源码】 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系…

线上SQL超时场景分析-MySQL超时之间隙锁

前言 之前遇到过一个由MySQL间隙锁引发线上sql执行超时的场景&#xff0c;记录一下。 背景说明 分布式事务消息表&#xff1a;业务上使用消息表的方式&#xff0c;依赖本地事务&#xff0c;实现了一套分布式事务方案 消息表名&#xff1a;mq_messages 数据量&#xff1a;3000多…

[java基础揉碎]基本数据类型转换

介绍 当java程序在进行赋值或者运算时&#xff0c;精度小的类型自动转换为精度大的数据类型&#xff0c; 这个就是自动类型转换。 数据类型按精度&#xff08;容量&#xff09;大小排序为: 自动类型转换注意和细节 1.有多种类型的数据混合运算时&#xff0c;系统首先自动…

【Linux的权限命令详解】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 shell命令以及运行原理 Linux权限的概念 Linux权限管理 一、什么是权限&#xff1f; 二、权限的本质 三、Linux中的用户 四、linux中文件的权限 4.1、文件访问…

【成本价特惠】招募证书代理:工信部、PMP、阿里云、华为等认证,机会难得!

扫码和我联系 亲爱的读者朋友们&#xff0c; 今天&#xff0c;我想和大家分享一个难得的机会。我们目前正在积极招募各类证书的代理&#xff0c;包括工信部的证书、PMP&#xff08;项目管理专业人士&#xff09;证书、阿里云证书、华为证书、OCP 证书、CFA 证书等。这些证书在…

C++入门学习(七)整型

整型就是整数类型的数据&#xff08;-1&#xff0c;0&#xff0c;1等等&#xff09; 数据类型占用空间取值范围short(短整型)2字节 (-2^15 ~ 2^15-1) 32768~32767 int(整型)4字节(-2^31 ~ 2^31-1)long(长整形) Windows为4字节, Linux为4字节(32位), 8字节(64位) (-2^31 ~ 2^31…

LiteAD对接FusionCompute

2、FA发放云桌面并与FC对接 &#xff08;1&#xff09;创建虚拟机模板 &#xff08;2&#xff09;创建虚拟机命名规则 &#xff08;3&#xff09;创建虚拟机组 &#xff08;4&#xff09;创建桌面组 &#xff08;5&#xff09;创建域用户和组&#xff08;就相当于在Microsoft …

基于SpringBoot Vue家政服务预约平台系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

【linux驱动】详细剖析第一个hello word驱动程序

文章目录 驱动程序的框架驱动程序的使用示例 驱动程序的框架 Linux 驱动的基本框架主要由模块加载函数&#xff0c;模块卸载函数&#xff0c;模块许可证声明&#xff0c;模块参数&#xff0c;模块导出符号&#xff0c;模块作者信息等几部分组成&#xff0c;其中模块参数&#…

C++——vector的使用及其模拟实现

vector的使用及其模拟实现 文章目录 vector的使用及其模拟实现1. vector的使用1.1 构造函数construct1.2 获取当前存储的数据个数size()和最大容量capacity()1.3 访问1.3.1 operator[]运算符重载1.3.2 迭代器访问1.3.3 范围for 1.4 容量相关reserve()和resize()1.5 增&#xff…

【趣味题-04】20240120百鸡百钱(遍历循环排除,类似加减法)

背景需求 题目 5&#xff1a;百鸡百钱 作者&#xff1a;阿夏 时间&#xff1a;2024年1月20日百鸡百钱 公鸡每只 5 元&#xff0c;母鸡每只 3 元&#xff0c;小鸡 3 只一元&#xff0c; 现要求用 100 元钱买 100 只鸡(三种类型的鸡都要买)&#xff0c; 问公鸡、母鸡、小鸡各买几…