C++开发基础——函数对象与std::function模板

std::function的简易实现 这样做固然可以,但是使用时我们是不是得传递这个模板类的模板参数,还是使用以上的例子,我们现在必须得这样使用这个模板类。模板类(函数)的实例化,是在 预处理之后,编译之前;模板参数从构造函数的模板参数,移动到类模板参数中去,扩大了作用域;时显示指定类型,这是比较合理的,也更符合使用习惯;这个成员变量的类型应该是和构造函数的模板参数一个类型(,这样就可以将辅助类的类模板参数存储在辅助类中,然后想办法在。,我们使用什么样的材料(模板参数),就会生成什么样的代码;有了以上的思考,我们知道,将模板参数的作用域从。 阅读详情

一,函数对象

1.函数对象的概念

函数对象可以像函数那样被直接调用。

函数对象(function objects)又被称为仿函数(functors)。

函数对象可以被当作一个值赋给另一个变量,也可以作为实参传递给其他函数,或者作为其他函数的返回结果。

函数对象与函数指针相似,函数对象的行为和函数差不多,但是与函数指针不同的是,函数对象是完整的类对象,里面包含着成员变量和多个成员函数。

函数对象的用法如下:

//class可以换成struct
class FunctionObjName

{
public:
    ReturnType operator()(ParamType1, ... , ParamTypeN){
        process code
    }
};

2.函数对象的应用

函数对象的实现,本质上是在类中完成函数调用运算符的重载。因此,使用函数对象的重点在于重载"operator()"。

使用函数对象的步骤: 

step.01: 新建一个类,在类中定义一个重载的函数调用运算符

class Less
{
public:
    bool operator()(int a,int b) const;
};
//Less类的成员函数:函数调用运算符operator()

step.02: 定义函数运算符operator()的具体操作

bool Less::operator()(int a, int b) const
{
    return a < b;
}

step.03: 新建一个函数对象,并像调用函数一样调用函数对象

Less less_obj;
const bool_is_less = less_obj(5, 6);

3.标准库中的函数对象

STL标准库中提供了很多函数对象的类模板,它们都包含在头文件functional中。

例如上面提到的Less类,可以使用标准库中的"std::less<int>less"。从C++14标准开始,可以省略类型实参,例如"std::less<>less"。

标准库中常见的函数对象:

调用方式样例:

//方式一,直接调用
std::cout << std::plus<int>()(4, 5) << std::endl;
//方式二,实例化一个新的类,然后调用
std::plus<int> plus_obj;
std::cout << plus_obj(4, 5) << std::endl;

4.函数对象的传参

关于调用的时候传参,使用函数指针的开发场景更多时候是通过回调函数(超链接)来实现的,但是使用函数对象的开发场景有更加简洁的传参方式,它可以将用户传的参数放在对象的成员变量中。

代码样例:

#include <cmath>
class Nearer
{
public:
    Nearer(int value):{
        n=value;
    }
    bool operator()(int a,int b) const {
        return std::abs(a - n) < std::abs(b - n);
    };
private:
    int n;
};

5.C++代码样例

Demo_1: 

#include <iostream>
#include <vector>
#include <cmath> //For std::abs()
//用于对vector中逐个元素进行操作的模板函数
template <typename T, typename Process_type>
const T* find_optimum(const std::vector<T>& values, Process_type process)
{
       if (values.empty())
              return nullptr;
       const T* res = &values[0];
       for (size_t i = 1; i < values.size(); ++i)
       {
              if (process(values[i], *res))
              {
                      res = &values[i];
              }
       }
       return res;
}

class Nearer
{
public:
       Nearer(int value): n(value){ }
       //重载函数调用运算符
       bool operator()(int a, int b) const {
              return std::abs(a - n) < std::abs(b - n);
       };
private:
       int n;
};

class Less
{
public:
       //重载函数调用运算符
       bool operator()(int a, int b) const {
              return a < b;
       }
};

int main()
{
       Less less_obj;
       std::vector<int> numbers{ 23, 18, 17, 66, 40, 50 };
      std::cout << "Minimum element: " << *find_optimum(numbers, less_obj) <<  std::endl;
      std::cout << "The number nearest 36 is: " << *find_optimum(numbers, Nearer(50))  << std::endl;
}

运行结果: 

Minimum element: 17
The number nearest 36 is: 50

Demo_2:

#include <iostream>
#include <vector>
#include <algorithm>
class MeanValue {
private:
       int num;
       int sum;
public:
       MeanValue() : num(0), sum(0) {
       }
       //function call
       void operator()(int elem) {
              ++num;
              sum += elem;
       }
       double get_mean_value() {
              return static_cast<double>(sum) / static_cast<double>(num);
       }
};
int main()
{
       std::vector<int> data_list = { 1, 2, 3, 4, 5, 6, 7, 8};
      MeanValue mv_obj = std::for_each(data_list.begin(), data_list.end(),  MeanValue());
       std::cout << "mean value: " << mv_obj.get_mean_value() << std::endl;
}

运行结果: 

mean value: 4.5

二,标准库中的std::function模板

1.std::function简介

std::function<>是C++11标准引入的类模板。

std::function<>专门用来包装可调用的函数对象。

在"<>"里面传入返回值类型和传参类型就可以开始使用std::function<>了。

std::function<>用法如下:

std::function<ReturnType(ParamType1, ... , ParamTypeN)>

std::function<>类模板的特点是,可以通过指定的类型参数,来统一处理设定返回值类型和参数类型

的各种函数对象。

std::function<int(int)> 可以用来专门调用返回值是int类型,形参是int类型的函数对象。

因此,有了std::function<>,不同实现的各种函数对象可以共用同一种调用形式(call signature)。

实例化以后的std::function<>,例如std::function<int(int)>,可以被理解为是某种特定调用形式的一个容器。

2.std::function具体用法

std::function<>被实例化以后可以调用:

普通函数

函数对象

lambda表达式。

用法演示:

应用场景:std::function<int(int, int)> 

 如下定义了返回值为int类型,传参为(int, int)的三种实现方式: 

add -->普通函数实现

mod -->lambda表达式实现

divide -->函数对象实现(struct某种程度上用法和对象一样)

int add(int i, int j){return i + j;}
auto mod = [](int i, int j){return i % j;};
struct divide
{
    int operator()(int m, int n)

    {
        return m / n;
    }
};

std::function调用它们的方式如下: 

//初始化
std::function<int(int, int)> f1 = add;
std::function<int(int, int)> f2 = divide();
std::function<int(int, int)> f3 = mod;
//调用
std::cout << f1(4, 2) << std::endl;
std::cout << f2(4, 2) << std::endl;
std::cout << f3(4, 2) << std::endl;

完整C++代码实现: 

#include <iostream>
#include<functional>
int add(int i, int j) { return i + j; }
auto mod = [](int i, int j) {return i % j; };
struct divide
{
    int operator()(int m, int n)
    {
           return m / n;
    }
};
int main()
{
    std::function<int(int, int)> f1 = add;
    std::function<int(int, int)> f2 = divide();
    std::function<int(int, int)> f3 = mod;
    std::function<int(int, int)> f4 = [](int i, int j) {return i * j; };;
    std::cout << f1(4, 2) << std::endl;
    std::cout << f2(4, 2) << std::endl;
    std::cout << f3(4, 2) << std::endl;
    std::cout << f4(4, 2) << std::endl;
}

运行结果:

6
2
0
8

3.C++代码样例

Demo_1:

#include <functional>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void execute(const vector<function<void()>>& fs)
{
    for (auto& f : fs)
        f();
}
void plain_old_func()
{
    cout << "I'm an old plain function" << endl;
}
class functor
{
public:
    void operator()() const

    {
        cout << "I'm a functor" << endl;
    }
};
int main()
{
    vector<function<void()>> x;
    x.push_back(plain_old_func);
    functor functor_instance;
    x.push_back(functor_instance);
    x.push_back([]()
        {
            cout << "I'm a lambda expression" << endl;
        });
    execute(x);
}

运行结果: 

I'm an old plain function
I'm a functor
I'm a lambda expression

Demo_2:

#include <iostream>   
#include <functional>   
int main() {
    // an array of functions:
    std::function<int(int, int)> fn[] = {
        std::plus<int>(),
        std::minus<int>(),
        std::multiplies<int>()
    };
    for (auto& x : fn) {
        std::cout << x(10, 5) << '\n';
    }
    return 0;
}

运行结果:

15
5
50

*补充:头文件functional在C++17标准中引入了std::invoke。

invoke可以不需要经过初始化操作,直接进行调用操作。

std::invoke具体使用方式参考如下代码:

#include <iostream>
#include <functional>
using namespace std;
void globalFunction()
{
    cout << "globalFunction ..." << endl;
}
class MyClass
{
public:
    void memberFunction(int data)
    {
        std::cout << "MyClass memberFunction ..." << std::endl;
    }
    static void staticFunction(int data)
    {
        std::cout << "MyClass staticFunction ..." << std::endl;
    }
};
int main(
{
    MyClass obj;
    std::invoke(&MyClass::memberFunction, obj, 100);
    std::invoke(&MyClass::staticFunction, 200);
    std::invoke(globalFunction);
    return 0;
}

运行结果:

MyClass memberFunction ...
MyClass staticFunction ...
globalFunction ...

三,参考阅读

《Beginning C++17, 5th Edition》
《C++ Primer Plus, 6th Edition》
《The C++ Standard Library, Second Edition》
《C++新经典》
  C/C++开发基础——函数指针&回调函数
https://www.oreilly.com/library/view/mastering-c-programming/
https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/

别再为自定义类型发愁了!C++ unordered_map 三种哈希函数写法保姆级教程 本文详细介绍了C++ unordered_map中使用自定义类型作为键时三种哈希函数的实现方法:std::function包装、函数对象和std::hash模板特化。通过对比分析各方法的优缺点和适用场景,帮助开发者解决自定义键值类型的哈希问题,提升代码性能和可维护性。 阅读详情

相关推荐

C++中的高阶函数:std::function

例如,std::function<void(int)>表示接收一个整数参数,并且不返回任何值的回调函数,std::function<std::string(const std::string&)>表示接收一个字符串参数,并且返回一个字符串的回调函数。std::function是一个通用的、多态的函数封装器,它的实例可以对任何可以调用的目标实体进行存储、复制和调用操作,包括普通函数、Lambda表达式、函数指针和带有operator()的类等。在这个例子中,我们首先使用了一个自由函数作为任务函数。

mj348940862的博客 2681

std::function详解

std::function详解

weixin_44378800的博客 4万+

C++中std::function详解和实战示例

场景描述回调机制可存储传入的回调函数(例如事件触发、完成通知)异步任务调度用作任务队列中的任务封装策略模式在运行时动态替换策略行为(如算法接口)通用函数接口支持用户传入任意处理逻辑,提高系统模块化应用用法类型线程池封装任意任务事件系统注册/触发事件响应回调插件接口动态注册功能实现或更复杂结构。

qq_36812406的博客 2466

C++ invoke与function的区别

`invoke` 是 C++17 标准引入的一个函数模板,用来调用可调用对象(Callable Object,如函数指针、函数对象、成员函数指针等)并返回结果。

qq_29426201的博客 906

C++ 学习之函数对象

/ 定义一个加法函数对象Add adder;// 创建函数对象// 调用函数对象return 0;// 自定义升序排序函数对象// 使用函数对象进行升序排序// 输出排序结果return 0;// 自定义字符串长度比较仿函数// 创建字符串长度比较仿函数对象// 判断第一个字符串的长度是否小于第二个字符串的长度return 0;通过这些示例,您可以看到如何使用函数对象关系仿函数来进行对象之间的关系判断。您可以使用标准库提供的函数对象关系仿函数(如和。

百锦再的博客 2万+

第3.8章 C++ 函数工作实战笔记:普通函数、回调函数、lambda等函数用法最全总结

本文摘要:文章系统介绍了C++中的可调用对象及其在自动驾驶定位算法中的应用。主要内容包括:1) 普通函数的基本结构、声明调用及参数传递方式选择原则;2) 函数模板实现泛型编程的方法;3) 回调函数的四种实现方式(函数指针、std::function、仿函数、bind联合使用);4) Lambda表达式语法与捕获机制;5) constexpr函数的编译期计算特性。文章结合自动驾驶场景,强调了合理选用可调用对象对提升代码模块化和性能的重要性,并提供了各类可调用对象的典型用法示例和最佳实践建议。(149字)

行知SLAM 97

C++笔记 function函数包装器模板

摘要 本文全面介绍了C++中的std::function,它是一种通用函数包装器,可以存储、复制和调用各种可调用对象(普通函数、lambda表达式、函数对象、成员函数等)。文章详细展示了std::function的基本用法,包括包装不同类型的可调用对象、状态检查、错误处理等。通过多个实际应用场景(如回调系统、策略模式、事件处理)演示了std::function的强大功能,并探讨了高级特性如函数组合和返回值类型推导。最后提供了性能考量和最佳实践建议,并展示了一个完整的计算器系统实现示例。std::functi

似流水般平静而坚定。 927

C++11 新特性 ④ | 模板类 std::function 和标准库函数 std::bind

详细讲解模板类std::function和标准库函数std::bind。

dvlinker的技术专栏 1万+

C++ std::function(函数封装器)详解

本文详细介绍了C++11中的std::function函数封装器。std::function是一个通用的函数包装器,可以存储、复制和调用各种可调用对象,包括普通函数、函数指针、lambda表达式、函数对象以及类成员函数(需配合std::bind)。文章从基本用法、状态检查、应用场景到注意事项进行了全面讲解,并比较了模板与std::function的适用场景。std::function在回调函数、策略模式等场景中非常有用,但需注意其性能开销和空状态检查。

本博客分享软硬件一体化开发实战。硬件涵盖 PCB 设计、STM32 等 MCU 底层开发;软件包含 C++、Rust,Qt/QML、PyQt、Slint、TouchGFX、LVGL 各类 GUI 框架。方便软硬件开发者查阅学习。欢迎关注! 853

Unity3D赛车游戏+脚本基础

本章主要介绍Unity的基础开发流程以及涉及到的概念。这个过程需要我们学会编写一些游戏脚本,在这讲的过程中我们会完成一个赛车小游戏,因此,在讲述这些基本概念和流程的时候,会同时涉及到一点脚本的开发基础.在游戏,电影和动画中,都有一个渲染的帧率,电影是24帧/s,游戏大概是30帧/s(当然也有60帧/s的)。在unity里面1秒钟,Update方法执行了30次。1秒钟有30帧,帧与帧之所消耗的时间是不一样的,那么我如何知道上一帧用了多少时间?Time.deltaTime就是为了解决这个问题。

m0_58367586的博客 7658

Windows10 使用Apple Studio Display显示器的设置

AppleStudioDisplay显示器购买花了近1.5wRMB,由于为windows台式机,显卡为NVIDAGTX-1660,而AppleStudioDisplay只有雷电接口,尝试了很多种转接方式,均以失败告终,最终使用贝尔金VR线成功,,附图如下这边也测试过NVIDARTX-2060Super、NVIDAGTX-1650显卡,都是能点亮的,NVIDA1650存在关机重启后黑屏,不稳定现象,2060也存在关机重启后不亮现象,后面发现1660s很稳定。...

爱意随风起,人生不可弃。 1万+

C++函数设计:从基础到实战,构建高效可维护代码

函数作为编程语言的核心概念,本质上是封装特定逻辑的代码单元,其设计质量直接影响软件的可维护性和性能。在C++中,函数不仅是执行任务的工具,更是实现代码复用、抽象和多态的基础。通过理解函数签名、参数传递机制(值、引用、指针)和返回策略,开发者可以编写出高效且安全的代码。现代C++进一步引入了Lambda表达式、std::function和函数模板等特性,极大地提升了代码的灵活性和表现力,尤其在事件回调、泛型编程等场景中价值显著。这些特性与函数式编程思想结合,使得C++能够应对从底层系统到高性能应用的多样化需求

weixin_30267785的博客 398

STM32F4三重ADC+DMA双缓冲实战:用CubeMX搞定同步采样,告别数据覆盖烦恼

本文详细介绍了STM32F4三重ADC与DMA双缓冲技术的实战应用,通过CubeMX配置实现同步采样,解决数据覆盖问题。内容涵盖硬件架构解析、CubeMX工程配置、双缓冲实现技巧及调试优化方法,适用于电机控制、电力监测等需要高精度多通道信号采集的场景。

weixin_30627341的博客 357

C++11核心特性全解:从C++98到现代C++的全面升级(万字总结)

C++11重点内容详解,必要性突破!

mogreat的博客 718

电子结构设计(EMD)十年知识总结

客官,你的面相是做结构设计的奇才~1. 材料选择【一出手的0.1s就败了】2. 钣金件设计【折来折去有啥难】3. 塑胶件设计【看着好复杂】4. 型材件设计【凭啥不让我设计】5. 电子结构(PCBA)设计【静电肿么要我背锅】6. 包装设计【要的就是金玉其外,败絮其中】7. 外观(工业)设计【好不好看,谁说了算】8. 标签设计【】9. 标准件选择【一个螺丝难倒英雄汉/提起螺丝,英雄气短】10. 计算仿...

wfeng86的博客 1569

UNITY3D万人同屏,Dots万人同屏解决方案_类萌宠宠之战

UNITY3D弹幕游戏开发,万人同屏解决方案

6472

C++工厂模式实现与应用详解

工厂模式是面向对象设计中最重要的创建型模式之一,它通过封装对象创建逻辑实现解耦,提升代码的可维护性和扩展性。在C++这种强类型语言中,工厂模式结合智能指针、模板等现代特性,可以构建类型安全且高效的对象创建体系。从简单工厂到注册式工厂,不同变体适用于不同场景,特别是在游戏开发、GUI框架和插件系统等需要动态创建对象的领域。现代C++的最佳实践包括使用unique_ptr管理生命周期、可变参数模板支持任意构造参数,以及与对象池结合优化性能。理解工厂模式的设计原理和C++特有实现方式,对于构建可扩展、高性能的软件

weixin_31292729的博客 325

用 SemanticObject 把字段变成可点击链接:Fiori Elements Navigation Using a Link 的工程化实践

SAP Fiori elements 通过 Common.SemanticObject 注解可将字段转为可点击链接,实现应用间跳转。当源字段名与目标属性名不一致时,需使用 Common.SemanticObjectMapping 进行映射。该功能依赖 Fiori Launchpad 的目标映射配置,确保正确解析 semantic object + action 并传递参数。常见误区包括未配置目标映射或字段映射错误,需逐一检查语义标注、intent 解析和参数传递链路。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 272

C++篇:别再用 C++98 了!C++11 这几个特性直接提升效率

核心本质有固定内存地址、能被取地址的值•右值:临时数据、没有固定地址、不能取地址的值C++11提供的可调用对象包装器,统一收纳函数、函数指针、仿函数、lambda 表达式。

2502_94387000的博客 913

DirectX function “GetDeviceRemovedReason“ failed with DXGI_ERROR_DEVICE_HUNG (“The GPU will not resp

游戏报错"DXGI_ERROR_DEVICE_HUNG"的解决方案 在使用RTX 40系显卡运行FIFA 23等游戏时,可能出现DirectX报错导致游戏崩溃。这主要由于最新显卡驱动与DirectX 12的兼容性问题。解决方法包括: 降级显卡驱动版本 修改游戏配置文件,将DIRECTX_SELECT设为1 在显卡控制面板中关闭垂直同步、抗锯齿、DLSS 3等功能 调整电源模式为性能优先 这些操作可以有效解决因驱动兼容性导致的游戏崩溃问题。

猿小白的博客 3890

Monorepo与pnpm:前端项目管理的完美搭档

pnpm又称 performant npm,翻译过来就是高性能的npm。Monorepo是一种项目开发与管理的策略模式,它代表"单一代码仓库"(Monolithic Repository)。在Monorepo模式中,所有相关的项目和组件都被存储在一个统一的代码仓库中,而不是分散在多个独立的代码仓库中,这些项目之间还可能会有依赖关系。

m0_68271787的博客 2562

【C++】std::function——或许是最简单易懂的讲解

这么多可调用对象,每次用的时候很麻烦(可调用对象如何使用?如果我们可以将其封装,取一个统一的名字,每次用这个统一的名字接住不同的可调用对象,岂不美哉?参考链接:https://blog.youkuaiyun.com/qq_37085158/article/details/124626913。std::function是C++11中引入的特性,是一个模板类,其头文件是functional。参考链接:https://blog.youkuaiyun.com/jusu10/article/details/121467274。

qq_42595835的博客 3827

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

用AI自动生成std::function代码,提升C++开发效率

实际体验中,平台的一键部署功能对于演示这类功能特别方便——写完代码直接生成可交互的演示页面,不用折腾本地环境配置。对于需要持续运行的服务端应用,部署按钮点一下就能上线测试,省去了至少半小时的Nginx配置时间。传统方式可能需要查半天文档才能写对的复杂绑定,现在动动嘴皮子就能搞定,开发效率的提升不是一点半点。简直天作之合,比如要实现一个带状态的计数器,只需几行代码就能创建包含私有计数变量的函数对象。的AI辅助功能,可以快速生成高质量的实现代码,效率直接翻倍。方法转化为可调用的函数对象。

NightshadeRaven21的博客 892

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【C++】C++11的std::function和std::bind用法详解

在设计回调函数的时候,无可避免地会接触到可回调对象。在C++11中,提供了std::function和std::bind两个方法来对可回调对象进行统一和封装。 可调用对象 C++中有如下几种可调用对象:函数、函数指针、lambda表达式、bind对象、函数对象。其中lambda表达式和bind对象是C++11标准中提出的(bind机制并不是新标准中首次提出,而是对旧版本中bind1st和bind2...

Yngz_Miao的博客 5万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++函数对象-函数包装器-(std::function)(一)- 构造新的 std::function 实例 - 析构 std::function 实例

从各种资源构造 std::function 。 1-2) 构造空 function 。 3-4) 复制 (3) 或移动 (4) other 的目标到 *this 的目标。若 other 为空,则调用后 *this 将亦为空。对于 (4) , other 在调用后处于合法但未指定的状态。 5) 以 std::move(f) 初始化目标。若 f 是空指针或指向成员的空指针,则 *this 在此调用后将为空。此构造函数不参与重载决议,除非 f 对于参数类型 Args... 和返回类型 R 可调用 (Call

qq_40788199的博客 1771
上一篇: C++开发基础——函数指针&回调函数
下一篇: C++开发基础——指针与引用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员与背包客_CoderZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值