C++11中std::function的使用

2023-11-02

类模版std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、以及其它函数对象等

通过std::function对C++中各种可调用实体(普通函数、Lambda表达式、函数指针、以及其它函数对象等)的封装,形成一个新的可调用的std::function对象,让我们不再纠结那么多的可调用实体。

std::function实现了一套类型消除机制,可以统一处理不同的函数对象类型。以前使用函数指针来完成这些,现在可以使用更安全的std::function来完成这些任务

C++11中推出std::function是为了泛化函数对象,函数指针,引用函数,成员函数的指针,让我们可以按更统一的方式写出更加泛化的代码。

std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(像函数指针这类可调用实体,是类型不安全的)。

可调用实体转换为std::function对象需要遵守以下两条原则:

(1)、std::function对象的参数能转换为可调用实体的参数;

(2)、可调用实体的返回值能转换为std::function对象的返回值(注意,所有的可调用实体的返回值都与返回void的std::function对象的返回值兼容)。

在C++中,”可调用对象”概念:(1)、是一个函数指针;(2)、是一个具有operator()成员函数的类对象(仿函数);(3)、是一个可被转换为函数指针的类对象;(4)、是一个类成员(函数)指针。

class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any Callable target -- functions,lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.

There are two performance implications of using std::function that might surprise you:

(1)、When calling a std::function, it does a virtual function call.

(2)、When assigning a lambda with significant captures to a std::function, it will do a dynamic memory allocation.

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "function.hpp"
#include <iostream>
#include <string>
#include <functional>
#include <vector>

///
// reference: http://en.cppreference.com/w/cpp/utility/functional/function
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 test_function1()
{
	// store a free function
	std::function<void(int)> f_display = print_num;
	f_display(-9);

	// store a lambda
	std::function<void()> f_display_42 = []() { print_num(42); };
	f_display_42();

	// store the result of a call to std::bind
	std::function<void()> f_display_31337 = std::bind(print_num, 31337);
	f_display_31337();

	// store a call to a member function
	//std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
	const Foo foo(314159);
	//f_add_display(foo, 1);

	// store a call to a data member accessor
	//std::function<int(Foo const&)> f_num = &Foo::num_;
	//std::cout << "num_: " << f_num(foo) << '\n';

	// store a call to a member function and object
	using std::placeholders::_1;
	std::function<void(int)> f_add_display2 = std::bind(&Foo::print_add, foo, _1);
	f_add_display2(2);

	// store a call to a member function and object ptr
	std::function<void(int)> f_add_display3 = std::bind(&Foo::print_add, &foo, _1);
	f_add_display3(3);

	// store a call to a function object
	std::function<void(int)> f_display_obj = PrintNum();
	f_display_obj(18);

	return 0;
}

///
// reference: https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/
void execute(const std::vector<std::function<void()>>& fs)
{
	for (auto& f : fs)
		f();
}

void plain_old_func()
{
	std::cout << "I'm an old plain function" << std::endl;
}

class functor
{
public:
	void operator()() const
	{
		std::cout << "I'm a functor" << std::endl;
	}
};

int test_function2()
{
	std::vector<std::function<void()>> x;
	x.push_back(plain_old_func);

	functor functor_instance;
	x.push_back(functor_instance);
	x.push_back([]()
	{
		std::cout << "HI, I'm a lambda expression" << std::endl;
	});

	execute(x);

	return 0;
}

///
// reference: http://shaharmike.com/cpp/lambdas-and-functions/
void global_f() {
	std::cout << "global_f()" << std::endl;
}

struct Functor {
	void operator()() { std::cout << "Functor" << std::endl; }
};

int test_function3()
{
	std::function<void()> f;
	std::cout << "sizeof(f) == " << sizeof(f) << std::endl;

	f = global_f;
	f();

	f = [](){ std::cout << "Lambda" << std::endl; };
	f();

	Functor functor;
	f = functor;
	f();

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11中std::function的使用 的相关文章

随机推荐

  • LeetCode05 最长回文子串 java(动态规划)

    题目 给定一个字符串 s 找到 s 中最长的回文子串 你可以假设 s 的最大长度为 1000 示例 1 输入 babad 输出 bab 注意 aba 也是一个有效答案 示例 2 输入 cbbd 输出 bb 分析 初始状态 dp i i 1
  • flex 中文API

    http help adobe com zh CN AS3LCR Flex 4 0
  • 微软服务器漏洞,微软SMBv3客户端/服务端远程代码执行漏洞(CVE-2020-0796)技术分析...

    微软安全中心在北京时间3月12日23时发布了影响Windows 10 等系统用户的SMBv3远程代码执行漏洞补丁 我们建议受影响的用户尽快按微软更新信息指南安装该补丁 https portal msrc microsoft com en U
  • openGL使用高度贴图模拟地球表面凹凸效果

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一 高度贴图是什么 二 代码 1 c 主程序 2 着色器程序 运行效果 源码下载 前言 不少模型都会附带以 bump 为名结尾的贴图 这种帖图统称为凹凸贴图 目的是为了体现
  • C++-求数组的最大值、最小值、求和

    关于C 求数组的最大值 最小值 求和 我最初以为只是用一个max min就可以 没想到是max element 不过采用vector 同样可以 include
  • vim插件:显示树形目录插件NERDTree安装 和 使用

    前言 一 下载和配置 NERDTree插件的官方地址如下 可以从这里获取最新的版本 https github com scrooloose nerdtree 下载zip安装包 或者使用下面官网源文件安装方法 我的实验环境是centos6 6
  • 安装win8/win10提示无法在驱动器0分区上安装windows解决方法

    在通过U盘或光盘安装win8 win8 1 win10系统时 不少用户遇到无法安装的问题 提示 无法在驱动器0的分区1上安装windows 格式化分区1也不能解决 进而提示Windows无法安装到这个磁盘 选中的磁盘采用GPT MBR分区形
  • 【Linux】文件操作

    文章目录 1 系统api和库函数关系 1 1内存结构 2 文件IO 2 1open函数 2 2close函数 实现简单的touch指令 2 3read 函数 2 4write 函数 实现cat指令 2 5lseek函数 2 6阻塞和非诸塞
  • 设置取消自动Build

    你一修改了代码 他就会building一下 你可以设置取消自动Build Project gt Build Automatically
  • mysql创建数据库1064_Mysql创建表过程中报1064错误

    Mysql创建表过程中报1064错误 发布时间 2020 06 18 06 23 08 来源 51CTO 阅读 7528 作者 白羊IT 我在自己搭建的mysql服务中 在使用create table创建表时报了1064错误 尝试网上找了各
  • openGL/openGLES glGetActiveUniform函数详解

    openGL官网文档 openGLES官网 Name glGetActiveUniform Returns information about an active uniform variable for the specified pro
  • Gateway网关-网关的cors跨域配置

    什么是跨域问题 跨域 域名不一致就是跨域 主要包括 域名不同 www taobao com 和 www taobao org 和 www jd com 和 miaosha jd com 域名相同 端口不同 localhost 8080和lo
  • 滤波算法比较

    滤波算法比较 1 限幅滤波法 又称程序判断滤波法 A 方法 根据经验判断 确定两次采样允许的最大偏差值 设为A 每次检测到新值时判断 如果本次值与上次值之差 lt A 则本次值有效 如果本次值与上次值之差 gt A 则本次值无效 放弃本次值
  • Android 批量初始化Button

    Button总是需要一个个设置监听响应点击事件 并在Activity中implements View OnClickListener 1 点击启动activity 2 点击执行方法 public class BaseActivity ext
  • 基于深度学习的主机操作系统识别

    无论从网络安全的攻击或是防护视角 信息的采集和甄别都至关重要 其中主机的系统类型是关键出发点 在以往经验中 根据操作系统类型往往能够大致判断其存在的风险点及风险类型 因此 识别主机操作系统类型对系统网络安全防护具有极其重要的意义 操作系统识
  • Verilog实现SPI通信(包括对任务和函数用法的讲解)

    一 基本知识 1 SPI SPI是串行外设接口 Serial Peripheral Interface 的缩写 它是一种高速的 全双工 同步的通信总线 并且在芯片的管脚上只占用四根线 SPI的通信原理很简单 它以主从方式工作 这种模式通常有
  • centos7 + ambari 2.6安装与系统配置过程记录

    继上一篇博客记录如何u盘安装centos centos7 u盘安装遇到的坑以及靠谱解决方法 继续写安装的ambari的过程 安装的过程主要是参考这个博客的 CentOS 7 4 安装 Ambari 2 6 0 HDP 2 6 3 搭建Had
  • torch.nn.Conv1d及一维卷积举例说明

    一维卷积不代表卷积核只有一维 也不代表被卷积的feature也是一维 一维的意思是说卷积的方向是一维的 class torch nn Conv1d in channels out channels kernel size stride 1
  • 【完全开源】小安派-Voice 内置音频开发板

    目录 一 概述 二 系统框图 三 电源管理模块 四 内置语音模块 五 GPIO引脚模块设计 六 资料 一 概述 AiPi Voice是安信可开源团队专门为Ai M61 32S设计的一款开发板 支持WiFi6 BLE5 3 所搭载的Ai M6
  • C++11中std::function的使用

    类模版std function是一种通用 多态的函数封装 std function的实例可以对任何可以调用的目标实体进行存储 复制 和调用操作 这些目标实体包括普通函数 Lambda表达式 函数指针 以及其它函数对象等 通过std func