C++ | function

news2024/10/7 8:22:37

C++ | function

文章目录

  • C++ | function
    • 引言
    • 实战
      • 1. 模板类声明
      • 2.普通函数/Lambda表达式/仿函数/类成员函数
      • 3.函数指针/模板函数/模板函数对象
      • 4.静态函数/类模板静态函数/模板类成员函数/类成员函数
      • 5. copy/move
    • Reference

引言

程序设计时,经常需要使用回调函数,如果针对每种不同的可调用对象或函数单独进行声明类型,代码会非常冗余

因此C++ 引入了std::function类模板,std::function对象实例可被拷贝,移动等,可以使用指定的调用特征来直接调用目标元素,不依赖于其元素自身的类型

该函数包装器模板能包装任何类型的可调用实体,如普通函数、函数对象、成员函数、静态函数、lamda表达式和函数对象等。

当std::function对象实例未包含任何实际可调用实体时,调用该std::function对象实例将抛出std::bad_function_call异常。

可调用对象(callable object)包括:

  • 函数
  • 函数指针
  • lambda 表达式
  • bind 创建的对象
  • 重载了函数调用运算符的类(仿函数)

实战

1. 模板类声明

简单说,std::function 就是提前存储了函数实体,在需要的时候回调出来即可。其入参和返回值均与被调用函数保持一致。

如果绑定函数实体的时候,还没确定函数参数,可以通过 std::bind 进行函数入参绑定,等到参数确定好,再传入合适的位置以供调用。

  /** _Res 是返回类型, _ArgTypes 是参数类型
   *  @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 = __invoke_result<_Func&, _ArgTypes...>>
	struct _Callable
	: __is_invocable_impl<_Res2, _Res>::type
	{ };

      // 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
      function() noexcept
      : _Function_base() { }

      function(nullptr_t) noexcept
      : _Function_base() { }

      function(const function& __x);

      function(function&& __x) noexcept : _Function_base()
      {
	__x.swap(*this);
      }

   // ======================= Randy 还有诸多成员函数 =======================

  
/** 只能和 nullptr 和 0 比较
   *  @brief Compares a polymorphic function object wrapper against 0
   *  (the NULL pointer). 
   *  @returns @c false if the wrapper has no target, @c true otherwise
   *
   *  This function will not throw an %exception.
   */
  template<typename _Res, typename... _Args>
    inline bool
    operator!=(const function<_Res(_Args...)>& __f, nullptr_t) noexcept
    { return static_cast<bool>(__f); }

  /// @overload
  template<typename _Res, typename... _Args>
    inline bool
    operator!=(nullptr_t, const function<_Res(_Args...)>& __f) noexcept
    { return static_cast<bool>(__f); }
          
          
    private:
      using _Invoker_type = _Res (*)(const _Any_data&, _ArgTypes&&...);
      _Invoker_type _M_invoker;
  };

因此,定义一个std::function 的时候,需要将入参及返回值传递给 std::function 模板类即可

std::function<std::string(int)> randy;
std::function<int(char,double)> sesame;

2.普通函数/Lambda表达式/仿函数/类成员函数

#include <iostream>
#include <functional>

// 普通函数
int commonFunc(int lhs, int rhs) {
	return lhs + rhs;
}

// Lambda表达式
auto lamdaFunc = [](int lhs, int rhs) {
	return lhs + rhs;
};

// 函数对象 换成 struct 亦可
class Functor {
public:
	int operator()(int lhs, int rhs) {
		return lhs + rhs;
	}
};


// 类成员函数
class Randy
{
public:
	// 1.类成员函数
	int RandyMemberFunc(int lhs, int rhs) { return lhs + rhs; }
	// 2.类静态成员函数
	static int RandyStaticFunc(int lhs, int rhs) { return lhs + rhs; }
};

int main() {
    // 定义一个 std::function 函数
    std::function<int(int, int)> qcj_CallBack;
    int result = -1;

	// 普通函数
	qcj_CallBack = commonFunc;
	result = qcj_CallBack(2, 1);
	std::cout << "common function: " << result << std::endl;

	// 普通函数指针
	qcj_CallBack = &commonFunc;
	result = qcj_CallBack(2 ,2);
	std::cout << "common function pointer: " << result << std::endl;

	// Lambda表达式
	qcj_CallBack = lamdaFunc;
	result = qcj_CallBack(2, 3);
	std::cout << "lambda function: " << result << std::endl;

	// 函数对象
	Functor functor_randy;
	qcj_CallBack = functor_randy;
	result = qcj_CallBack(2, 4);
	std::cout << "function object: " << result << std::endl;

	// 类成员函数(使用std::bind绑定类成员函数, std::placeholders::_2为占位符,顺序与原函数入参对应,次序可调换)
             // qcj_CallBack = std::bind(&Randy::RandyMemberFunc, randy, std::placeholders::_2, std::placeholders::_1);
            // 上式这么写也可以,调用时 第2个入参在前,第1个入参在后
	Randy randy;
	qcj_CallBack = std::bind(&Randy::RandyMemberFunc, randy, std::placeholders::_1, std::placeholders::_2);
	result = qcj_CallBack(2, 5);
	std::cout << "class member function: " << result << std::endl;

	// 类静态成员函数
	qcj_CallBack = Randy::RandyStaticFunc;
	result = qcj_CallBack(2, 6);
	std::cout << "class static member function: " << result << std::endl;

	return 0;
}

结果:

common function: 3
common function pointer: 4
lambda function: 5
function object:: 6
class member function: 7
class static member function: 8

3.函数指针/模板函数/模板函数对象

#include <iostream>
#include <functional>

// 回调函数
std::function<std::string(std::string)> RandyFuncCallBack;

// 函数指针
std::string (*RandyFuncPtr)(std::string);

template<typename T>
T RandyTemplate(T t_arg){
    return "三戒纪元: " + t_arg;
}

// 模板函数对象
template <typename T>
struct RandyStruct{
    T operator()(T t_arg){
        return "Randy struct: " + t_arg;
    }
};

int main(int argc, char *argv[]){
    //std::function包装模板函数
    RandyFuncCallBack = RandyTemplate<std::string>; 
    std::cout << RandyFuncCallBack("std::function called.") << std::endl; 
    
    // 函数指针
    RandyFuncPtr = RandyTemplate;
    RandyFuncCallBack = RandyFuncPtr;
    std::cout << RandyFuncCallBack("function ptr called.") << std::endl;
    
    // 模板函数对象
     RandyFuncCallBack = RandyStruct<std::string>(); 
    std::cout << RandyFuncCallBack("struct function called.") << std::endl;
    return 0;
}

结果:

三戒纪元: std::function called.
三戒纪元: function ptr called.
Randy struct: struct function called.

4.静态函数/类模板静态函数/模板类成员函数/类成员函数

#include <iostream>
#include <functional>

// 回调函数
std::function<std::string(std::string)> RandyFuncCallBack;

// 类成员函数
struct Randy{
    std::string RandyCommonFunc(std::string sesame){
        return "Randy common function: " + sesame;
    }

    static std::string RandyStaticFunc(std::string t_arg){
        return "Randy static function: " + t_arg;
    }
};

// 模板类
template <typename T>
struct RandyTemplateStruct{
    // 模板对象函数
    T RandyTemplateFunc(T sesame){
        return "Randy Template function: " + sesame;
    }

    // 模板对象静态函数
    static T RandyTemplateStaticFunc(T t_arg){
        return "Randy Template static function: " + t_arg;
    }
};

int main(int argc, char *argv[]){
    Randy randy;

    // 类成员函数
    RandyFuncCallBack = std::bind(&Randy::RandyCommonFunc, &randy, std::placeholders::_1); 
    std::cout << RandyFuncCallBack("RandyCommonFunc called.") << std::endl; 

    // 类成员函数
    RandyFuncCallBack = randy.RandyStaticFunc;
    std::cout << RandyFuncCallBack("RandyStaticFunc called.") << std::endl; 

    // 模板对象函数
    RandyTemplateStruct<std::string> randyTemplate;
    RandyFuncCallBack = std::bind(&RandyTemplateStruct<std::string>::RandyTemplateFunc, &randyTemplate, std::placeholders::_1); 
    std::cout << RandyFuncCallBack("RandyTemplateFunc called.") << std::endl; 

    // 模板对象静态函数
    RandyFuncCallBack = RandyTemplateStruct<std::string>::RandyTemplateStaticFunc;
    std::cout << RandyFuncCallBack("RandyTemplateStaticFunc called.") << std::endl; 
    return 0;
}

结果:

Randy common function: RandyCommonFunc called.
Randy static function: RandyStaticFunc called.
Randy Template function: RandyTemplateFunc called.
Randy Template static function: RandyTemplateStaticFunc called.

5. copy/move

#include <iostream>
#include <functional>

// 回调函数
std::function<std::string(std::string)> RandyFuncCallBack;

std::string PrintRandy(std::string sesame) {
	return ">>>>>>>>>> 三戒纪元: " + sesame + " <<<<<<<<<<";
}


int main(int argc, char *argv[]){
    // 未包装任何对象实体
    std::cout << RandyFuncCallBack("RandyFuncCallBack") << std::endl;
    // 结果为:Aborted (core dumped)
    
    RandyFuncCallBack = PrintRandy;
    std::cout << RandyFuncCallBack("RandyFuncCallBack") << std::endl;

     //拷贝
    std::function<std::string(std::string)> CallBack_Copy(RandyFuncCallBack);
    std::cout << CallBack_Copy("CallBack_Copy") << std::endl;
    
    //拷贝赋值运算符
    std::function<std::string(std::string)> CallBack_CopyAssign = RandyFuncCallBack; 
    std::cout << CallBack_CopyAssign("CallBack_CopyAssign.") << std::endl;

    //移动赋值运算符
    std::function<std::string(std::string)>&& CallBack_MoveAssign = std::move(RandyFuncCallBack); 
    std::cout << CallBack_MoveAssign("CallBack_MoveAssign") << std::endl;
    std::cout << RandyFuncCallBack("RandyFuncCallBack") << std::endl;

    return 0;
}

结果:

>>>>>>>>>> 三戒纪元: RandyFuncCallBack <<<<<<<<<<
>>>>>>>>>> 三戒纪元: CallBack_Copy <<<<<<<<<<
>>>>>>>>>> 三戒纪元: CallBack_CopyAssign. <<<<<<<<<<
>>>>>>>>>> 三戒纪元: CallBack_MoveAssign <<<<<<<<<<
>>>>>>>>>> 三戒纪元: RandyFuncCallBack <<<<<<<<<<

Reference

  • 【C++11 新特性】function(一)

  • C++ std::function详解与实战


欢迎关注公众号【三戒纪元】

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

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

相关文章

多语言支持-唯一客服系统文档中心

客服系统支持多语种展示&#xff0c;比如&#xff1a;中文&#xff0c;英文&#xff0c;繁体&#xff0c;日语&#xff0c;韩语&#xff0c;俄语等&#xff0c;并且可以扩展各种小语种 语种展示的优先级 首先&#xff0c;按照url参数中指定的lang参数 其次&#xff0c;查询loca…

Open5gs学习笔记

目录 1.用户面和控制面分离 最近想在liunx模拟机上运行Open5GSUERANSIM来学习5G信令流程。 1.用户面和控制面分离 open5GS的quickstart提及By having the control and user planes physically separated like this, it means you can deploy multiple user plane servers in …

灾难恢复:支持业务连续性的策略——保证员工和客户始终可以访问关键数据和应用程序

灾难恢复&#xff1a;支持业务连续性的策略 保证员工和客户始终可以访问关键数据和应用程序。 为什么选择 NetApp 的业务连续性和灾难恢复解决方案&#xff1f; 保持弹性&#xff0c;自如操作 NetApp 就在您身边&#xff0c;在这样一个跌宕起伏的时期竭诚帮助您实现业务连续性…

一秒钟变身明星:用swapface软件体验星光熠熠的感觉!

你是否曾经想过能够用电脑或手机来实时地将自己的面部与其他人或角色进行交换&#xff1f;你是否曾经想过能够用一款简单易用的软件来制作出有趣或惊艳的面部交换直播、视频或图片&#xff1f;如果你的答案是肯定的&#xff0c;那么你一定要试试swapface软件&#xff0c;这是一…

Linux服务器内核崩溃问题分析

阿里云服务器无法使用SSH连接&#xff0c;网站访问也出现异常&#xff0c;登录阿里云平台&#xff0c;系统提示&#xff1a;系统出现了内核Panic&#xff0c;OOM异常或内部宕机、性能抖动。后台询问了阿里云客服&#xff0c;说需要安装和开kdump 服务&#xff0c;于是开始了kdu…

九耶丨阁瑞钛伦特-springcloud(八)

SpringCloud体系结构是一个基于Spring框架的云原生微服务架构。它具有高可用性、高可扩展性、低时延和高安全性等特点&#xff0c;能够帮助企业构建高效、快速、安全、可靠的微服务体系架构&#xff0c;并支持跨云供应商和私有数据中心的部署。 SpringCloud体系结构的核…

2023 年第八届数维杯数学建模挑战赛 赛题浅析

为了更好地让大家本次数维杯比赛选题&#xff0c;我将对本次比赛的题目进行简要浅析。本次比赛的选题中&#xff0c;研究生、本科组请从A、B题中任选一个 完成答卷&#xff0c;专科组请从B、C题中任选一个完成答卷。这也暗示了本次比赛的难度为A>B>C 选题人数初步估计也…

windows网络常用命令,须熟记。

目录&#xff1a; 常用网络命令&#xff08;一&#xff09;-- ping操作 常用网络命令&#xff08;二&#xff09;-- IPConfig操作 常用网络命令&#xff08;三&#xff09;-- netstat 命令 和 tracert 命令 常用网络命令&#xff08;四&#xff09;-- route 命令 和 arp 命令 常…

视频国标GB28181及一个相关平台的应用

一、国标GB28181 1、概述 所谓国标GB28181&#xff0c;是我国制订的一项视频流接入协议。好处是&#xff0c;只要摄像头支持该项协议&#xff0c;那么无论是海康还是大华&#xff0c;或者别的什么摄像头&#xff0c;都能接入一个支持该协议的媒体平台&#xff0c;达到无缝集成…

USB Type-C接口会成为显示器行业的下个风口吗?

最近市场上开始陆续涌现配有USB-C接口的显示器&#xff0c;很多小伙伴并不知道这接口是什么用途。除一些老旧设备使用VGA外&#xff0c;目前显示器常用接口不外乎HDMI、DP、DVI这几种&#xff0c;但很多人并不知道&#xff0c;USB-C也是显示器接口之一。 为什么选择 USB-C&…

ubuntu下vlan使用配置

文章目录 一&#xff1a;什么是vlan1 &#xff1a;为什么使用vlan 二&#xff1a;ubuntu下vlan配置1: ubuntu启用配置vlan前的准备2&#xff1a;ip命令添加配置网卡3&#xff1a;vlan相关命令配置4&#xff1a;ubuntu 20.04 通过netplan配置及持久化5&#xff1a;ubuntu 18.04 …

linux环境安装使用jdk详解

01-安装JDK 1.1 下载jdk压缩包 下载地址&#xff1a; Oracle Access Manager Operation Error Java Downloads | Oracle 下载完成之后上传到服务器 # 1.将JDK解压缩到指定目录 tar -zxvf jdk-8u171-linux-x64.tar.gz -C /usr/ 注意:-C参数是将JDK解压之后文件放入usr目录中 # 2…

第43讲: Python使用map和filter函数遍历可迭代对象

文章目录 1.遍历迭代对map和filter函数的区别2.使用map函数对可迭代对象进行遍历3.使用filter函数对可迭代对象进行遍历 1.遍历迭代对map和filter函数的区别 map和filter这两个函数都可以根据指定的另外一个函数&#xff0c;从而对指定的可迭代对象&#xff08;列表、字符串、…

哪款蓝牙耳机舒适度最好?舒适度好的蓝牙耳机推荐

蓝牙耳机现在早就成为年轻人生活必备品&#xff0c;尤其是在通勤路上、大街上&#xff0c;基本都随处可见耳朵上挂着的小蓝牙设备&#xff0c;本文针对每种类型的蓝牙耳机&#xff0c;推荐了几款佩戴舒适度高的蓝牙耳机。 第一款、南卡小音舱Lite2蓝牙耳机 售价&#xff1a;2…

LeetCode_二叉树_简单_112.路径总和

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum。判断该树中是否存在 根节点到叶子节点的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum。如果存在&#xff0c;返回 true&#…

【KVM虚拟化】· virsh文件管理

目录 &#x1f341;离线访问工具应用场景 &#x1f341;离线命令 &#x1f342;virt-inspector &#x1f342;virt-cat &#x1f342;virt-edit &#x1f342;virt-df &#x1f342;virt-copy-out &#x1f342;virt-copy-in &#x1f342;guestfish &#x1f342;guestmount &…

TCP协议补充实验

目录 一、理解CLOSE_WAIT状态 二、理解TIME_WAIT状态 解决TIME_WAIT状态引起的bind失败的方法 三、 理解listen的第二个参数 四、SYN洪水 五、TCP、UDP对比 六、优化UDP实现可靠传输&#xff08;面试题&#xff09; 一、理解CLOSE_WAIT状态 当客户端和服务器在进行TCP通…

记录--Vue3+TS(uniapp)手撸一个聊天页面

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 Vue3TS(uniapp)手撸一个聊天页面 前言 最近在自己的小程序中做了一个智能客服&#xff0c;API使用的是云厂商的API&#xff0c;然后聊天页面...嗯&#xff0c;找了一下关于UniApp(vite/ts)版本的好像不…

Linux常用命令——ifconfig命令

在线Linux命令查询工具 ifconfig 配置和显示Linux系统网卡的网络参数 补充说明 ifconfig命令被用于配置和显示Linux内核中网络接口的网络参数。用ifconfig命令配置的网卡信息&#xff0c;在网卡重启后机器重启后&#xff0c;配置就不存在。要想将上述的配置信息永远的存的电…

如何用Facebook为你的跨境电商店铺进行引流?

对于跨境电商店铺来说&#xff0c;引流客户代表着潜在的商业机会和利润。当更多潜在客户访问你的店铺并下单购买产品时&#xff0c;这将增加你的销售额和利润&#xff0c;并帮助你的品牌影响力不断扩大。 一、Facebook广告付费玩法 1.创建一个Facebook商业页面&#xff1a;首先…