【C++】std::bind与functional函数对象

functional

文章目录

  • functional
    • std::bind
      • 使用示例
    • std::function
      • 类模板
      • 成员函数
      • 使用
      • 推导指引(C++17 起)

std::bind

原型:

template< class R, class F, class... Args >
constexpr /* 未指定 */ bind( F&& f, Args&&... args );

函数模板 std::bind 生成 f 的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用 f

  • f — 可调用 (Callable) 对象(函数对象、指向函数指针、到函数引用、指向成员函数指针或指向数据成员指针)
  • args ---- 要绑定的参数列表,未绑定参数会被命名空间 std::placeholders 的占位符 _1,_2, _3… 替换

使用示例

#include <functional>
#include <iostream>
#include <memory>
#include <random>void f(int n1, int n2, int n3, const int& n4, int n5)
{std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}int g(int n1)
{return n1;
}struct Foo
{void print_sum(int n1, int n2){std::cout << n1 + n2 << '\n';}int data = 10;
};int main()
{using namespace std::placeholders;  // 对于 _1, _2, _3...std::cout << "参数重排序和按引用传递:";int n = 7;// ( _1 与 _2 来自 std::placeholders ,并表示将来会传递给 f1 的参数)//std::cref返回需要被包装的到对象的左值引用,返回后面n的值auto f1 = std::bind(f, _2, 42, _1, std::cref(n), n);n = 10;f1(1, 2, 1001); // 1 为 _1 所绑定, 2 为 _2 所绑定,不使用 1001// 进行到 f(2, 42, 1, n, 7) 的调用std::cout << "嵌套 bind 子表达式共享占位符:";auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);f2(10, 11, 12); // 进行到 f(12, g(12), 12, 4, 5); 的调用std::cout << "绑定指向成员函数指针:";Foo foo;auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);f3(5);std::cout << "绑定是指向成员函数指针的 mem_fn:";auto ptr_to_print_sum = std::mem_fn(&Foo::print_sum);auto f4 = std::bind(ptr_to_print_sum, &foo, 95, _1);f4(5);std::cout << "绑定指向数据成员指针:";auto f5 = std::bind(&Foo::data, _1);std::cout << f5(foo) << '\n';std::cout << "绑定是指向数据成员指针的 mem_fn:";auto ptr_to_data = std::mem_fn(&Foo::data);auto f6 = std::bind(ptr_to_data, _1);std::cout << f6(foo) << '\n';std::cout << "使用智能指针调用被引用对象的成员:";std::cout << f6(std::make_shared<Foo>(foo)) << '\n'<< f6(std::make_unique<Foo>(foo)) << '\n';
}

输出:

参数重排序和按引用传递:2 42 1 10 7
嵌套 bind 子表达式共享占位符:12 12 12 4 5
绑定指向成员函数指针:100
绑定是指向成员函数指针的 mem_fn:100
绑定指向数据成员指针:10
绑定是指向数据成员指针的 mem_fn:10
使用智能指针调用被引用对象的成员:10
10

std::function

类模板 std::function 是通用多态函数包装器。 std::function 的实例能存储、复制及调用任何可复制构造的可调用目标——函数(通过其指针)、 lambda 表达式、 bind 表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针。

存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。

  • 实际上时对函数指针的优化
typedef  void*ptr)(intint// 这里的ptr就是一个函数指针|||V
std::function<void(int ,int)> func;
  • 头文件
#include <functional>

类模板

template< class R, class... Args >
class function<R(Args...)>;
  • R: 被调用函数的返回类型
  • Args…:被调用函数的形参

成员函数

  • 构造函数

从各种资源构造 std::function

  • 析构函数

销毁 std::function 对象。若 std::function 非空,则亦销毁其目标。

  • operator=

赋值新目标给 std::function 。

  1. 赋值 other 的目标副本,如同以执行 function(other).swap(*this);
  2. 移动 other 的目标到 *this 。 other 在有未指定值的合法状态。
  3. 舍弃当前目标。 *this 在调用后为空。
template< class F >
function& operator=( std::reference_wrapper<F> f ) noexcept;
  • swap

交换 *this 与 other 存储的可调用对象。

  • operator bool

检查是否包含了有效的目标

  • operator()

调用其目标

  • target_type

返回存储的函数的类型。

  • target

返回指向存储的可调用函数目标的指针。

使用

#include <functional>
#include <iostream>struct Foo {Foo(int num) : num_(num) {}void print_add(int i) const { std::cout << num_+i << '\n'; }int num_;
};void print_num(int i)
{std::cout << i << '\n';
}struct PrintNum {void operator()(int i) const{std::cout << i << '\n';}
};int main()
{// 存储自由函数std::function<void(int)> f_display = print_num;f_display(-9);//-9// 存储 lambdastd::function<void()> f_display_42 = []() { print_num(42); };f_display_42();//42// 存储到 std::bind 调用的结果std::function<void()> f_display_31337 = std::bind(print_num, 31337);f_display_31337();//31337// 存储到成员函数的调用std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;const Foo foo(314159);//创建FOO对象f_add_display(foo, 1);//314160f_add_display(314159, 1);//314160// 存储到数据成员访问器的调用std::function<int(Foo const&)> f_num = &Foo::num_;std::cout << "num_: " << f_num(foo) << '\n'; //num_: 314159// 存储到成员函数及对象的调用using std::placeholders::_1;std::function<void(int)> f_add_display2 = std::bind( &Foo::print_add, foo, _1 );f_add_display2(2);//314161// 存储到成员函数和对象指针的调用std::function<void(int)> f_add_display3 = std::bind( &Foo::print_add, &foo, _1 );f_add_display3(3);//314162// 存储到函数对象(仿函数)的调用std::function<void(int)> f_display_obj = PrintNum();f_display_obj(18);//18//递归使用std::function<int(int)> factorial = [&](int i) -> int{if(i == 1)return 1;return i * factorial(i - 1);};for (int i{5}; i != 8; ++i) { std::cout << i << "! = " << factorial(i) << ";  "; }
}

其他:

#include <functional>
#include <iostream>
#include <string>int f(int, int) { return 1; }
int g(int, int) { return 2; }void test(std::function<int(int, int)> const& arg)
{int (*const* ptr)(int, int) = arg.target<int(*)(int, int)>();if (ptr && *ptr == f)std::cout << "it is the function f\n";if (ptr && *ptr == g)std::cout << "it is the function g\n";
}int main()
{test(std::function<int(int, int)>(f));test(std::function<int(int, int)>(g));std::function<int(int,int)> fn1(f),fn2([](int a , int b) {return a+b;});std::cout << fn1.target_type().name() << '\n'<< fn2.target_type().name() << '\n';
}

输出结果:

it is the function f
it is the function g
PFiiiE
Z4mainEUliiE_

推导指引(C++17 起)

#include <functional>
int func(double) { return 0; }
int main() {std::function f{func}; // 指引 #1 推导 function<int(double)>int i = 5;std::function g = [&](double) { return i; }; // 指引 #2 推导 function<int(double)>
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何通过TortoiseGit可视化工具查看Git管理的版本树和信息(工作树变更)内容

一、版本树 黑色直线&#xff1a;master分支和基于master分支拉取基础分支都在这条线上&#xff0c;是一条直线。 其他线条&#xff1a;新开分支一定会增加一条线&#xff0c;但不一定每一条线分别代表一个分支。 注&#xff1a;如果一直是一个人&#xff0c;在同一个本地分支…

(三)Java 基本数据类型

目录 一. 前言 二. 基本数据类型 2.1. char&#xff08;字符型&#xff09; 2.2. byte&#xff08;字节型&#xff09; 2.3. short&#xff08;短整型&#xff09; 2.4. int&#xff08;整型&#xff09; 2.5. long&#xff08;长整型&#xff09; 2.6. float&#xff…

powerbuilder游标的使⽤

在某些PowerBuilder应⽤程序的开发中,您可能根本⽤不到游标这样⼀个对象。因为在其它⼯具开发中很多需⽤游标实现的⼯作,在PowerBuilder中却已有DataWin-dow来代劳了。事实上,DataWindow不仅可以替代游标进⾏从后台数据库查询多条记录的复杂操作,⽽且还远不⽌这些。但是同DataW…

前端如何设置模板参数

1.背景&#xff1a; 最近接到一个需求&#xff0c;在一个类似chatGpt的聊天工具中&#xff0c;要在对话框中设置模板&#xff0c;后端提供了很多模板参数&#xff0c;然后要求将后端返回的特殊字符转成按钮&#xff0c;编辑完成后在相应的位置拼接成字符串。 2.效果&#xff1a…

C++ 类模板

目录 前言 类模板语法 类模板和函数模板的区别 类模板没有自动类型推导的使用方式 类模板在模板参数列表中可以有默认参数 类模板中成员函数创建时机 类模板对象做函数参数 指定传入的类型 参数模板化 整个类模板化 类模板与继承 类模板成员函数类外实现 类模板分…

在Spring Cloud中使用OpenFeign完成从一个微服务上传到另一个微服务中

跨服务上传文件&#xff0c;嘿嘿&#xff0c;来一篇实用性高的&#xff0c;本篇将主要完成在Feign中上传文件到另一个微服务中。步骤如下&#xff1a; 我们需要在服务提供者和服务消费者的项目中添加相应的依赖&#xff1a; 对于服务提供者的项目&#xff0c;你需要添加Sprin…

Redis设计与实现之集合及有序集

目录 一、集合 1、编码的选择 2、编码的切换 3、 字典编码的集合 4、集合命令的实现 5、 求交集算法 6、求并集算法 7、 求差集算法 二、有序集 1、编码的选择 2、编码的转换 3、ZIPLIST 编码的有序集 4、SKIPLIST 编码的有序集 三、如何添加元素到集合或有序集中…

Next.js 学习笔记(二)——项目结构

Next.js 项目结构 此页面提供了 Next.js 项目的文件和文件夹结构的概述。它涵盖了 app 和 pages 目录中的顶级文件和文件夹、配置文件以及路由约定。 顶级文件夹 文件夹名描述appApp RouterpagesPages Routerpublic待服务的静态资源src可选的应用程序源文件夹 顶级文件 文…

万兆网络之屏蔽线序接法(中)

在介绍优质网线选购之前&#xff0c;先简单介绍一下水晶头 1毛钱一颗跟1元一颗的水晶头&#xff0c;往往是金手指厚度差别&#xff0c;你可以想象压制的时候可能会有什么情况 另外&#xff0c;一些3元一颗的镀金水晶头会有15U、30U之类的是电镀厚度单位&#xff0c;数值越大镀…

React Native面试题总结

1,简单介绍下React Native,以及和React.js的区别 React Native是一个JavaScript框架,由Facebook开发,以满足日益增长的移动应用开发的需求。它是开源的,基于JavaScript的。它被设计为用可重复使用的组件构建本地移动应用程序。它使用了大量的ReactJS组件,但在不同的设备…

文档安全加固:零容忍盗窃,如何有效预防重要信息外泄

文档安全保护不仅需要从源头着手&#xff0c;杜绝文档在使用和传播过程中产生的泄密风险&#xff0c;同时还需要对文档内容本身进行有效的保护。为了防范通过拷贝、截屏、拍照等手段盗窃重要文档内容信息的风险&#xff0c;迅软DSE加密软件提供了文档加密保护功能&#xff0c;能…

10 新字符设备驱动文件

一、新字符设备驱动原理 因为 register_chrdev 和 unregister_chrdev 两个函数是老版本驱动文件&#xff0c;现在可以用新字符设备驱动 API 函数。 1. 分配和和释放设备号 使用 register_chrdev 函数注册字符设备的时候只需要给定一个主设备号即可&#xff0c;但是这样会带来两…

如何计算2的n次方

今天在写代码的时候&#xff0c;遇到了纹饰评分的计算&#xff0c;纹饰的等级和评分的关系为&#xff1a; 1级纹饰&#xff1a;202级纹饰&#xff1a;403级纹饰&#xff1a;80 得出纹饰等级grade和纹饰评分score的关系&#xff1a;score (2 ^ grade) * 10&#xff0c;所以就…

git 不小心操作 reset current branch to here后,怎么还原

可以通过reflog来进行恢复&#xff0c;前提是丢失的分支或commit信息没有被git gc清除 一般情况下&#xff0c;gc对那些无用的object会保留很长时间后才清除的 可以使用git reflog show或git log -g命令来看到所有的操作日志 恢复的过程很简单&#xff1a; 通过git log -g命…

信息安全和网络安全的区别

信息安全与网络安全都属于安全领域&#xff0c;但它们的范围和重点不同。 信息安全主要关注数据的保护&#xff0c;包括对敏感数据进行加密、防止数据丢失或泄露等措施。信息安全通常与数据存储、传输和处理相关。 而网络安全更侧重于保护计算机系统和网络免受攻击、病毒、蠕…

Mac安装软件显示文件已损坏处理方法

今天安装软件&#xff0c;突然遇到了文件已损坏&#xff0c;扔到废纸篓的情况&#xff0c;于是搜索了下解决办法&#xff0c;跟大家分享下&#xff0c;希望对你有所帮助 一、检查安全性设置 打开【设置】-【隐私与安全】&#xff0c;下拉找到安全性&#xff0c;将安全性更改为…

自定义指令Custom Directives

<script setup langts> import { ref } from "vue"const state ref(false)/*** Implement the custom directive* Make sure the input element focuses/blurs when the state is toggled* */ // 以v开头的驼峰式命名的变量都可以作为一个自定义指令 const VF…

System作为系统进程陔如何关闭?

一、简介 system进程是不可以关闭的&#xff0c;它是用来运行一些系统命令的&#xff0c;比如reboot、shutdown等&#xff0c;以及用来运行一些后台程序&#xff0c;比如ntfs-3g、v4l2loopback等。system进程也被用于运行一些内核模块&#xff0c;比如nvidia、atd等。system进程…

mars3d加载arcgis发布的服务,⽀持4523坐标

问题 1.从这个服务地址加载&#xff0c;具体在哪⾥去转坐标呢&#xff1f; 加个 usePreCachedTilesIfAvailable&#xff1a;false 参数即可 坐标系为4490的arcgis影像服务图层&#xff0c;配置后瓦片加载不出来&#xff0c;没报错 甚至可以跳转 没有看出问题&#xff0c;或者测…

linux系统启动时运行web程序

1.修改rc.local文件 执行命令如果找不到会报错command not found &#xff0c;使用全路径即可 找不到的话 可以使用which 命令 找到路径 后台查看执行日志 2.修改rc.local文件的权限 chmod x rc.local 然后reboot 可以查到进程和启动日志