当前位置: 首页 > news >正文

[原创](Modern C++)现代C++的关键性概念: std::mem_fn是std::bind的轻量级版本, 它们的区别是什么?

[作者]
常用网名: 猪头三
出生日期: 1981.XX.XX
企鹅交流: 643439947
个人网站: 80x86汇编小站
编程生涯: 2001年~至今[共24年]
职业生涯: 22年
开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、
开发工具: Visual Studio、Delphi、XCode、C++ Builder、Eclipse
技能种类: 逆向 驱动 磁盘 文件 大数据分析
涉及领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全/macOS应用软件安全
项目经历: 股票模型量化/磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测
专注研究: 机器学习、股票模型量化、金融分析

[序言]
在现代C++编程中, 函数对象和回调机制被广泛应用, 尤其是在泛型编程和并发编程中, 将成员函数和成员变量进行绑定变得十分常见. 传统上, 可以使用std::bind来将类成员函数绑定为可调用对象, 但它在功能强大的同时, 也会引入一定的复杂性和额外开销. 相对而言, std::mem_fn提供了一种更轻量级的解决方案, 专注于将成员函数或成员变量转换为可调用对象, 从而在简单场景下获得更清晰和高效的实现.

[代码演示]

#include <iostream>
#include <memory>
#include <functional>
#include <fcntl.h>
#include <io.h>
#include <cwchar>

struct MEM_FN
{
    // 无参成员函数, 返回一个宽字符字符串
    std::wstring mpu_display_Str()
    {
        return L"Hello World";
    }

    // 带有1个参数的成员函数, 返回输入参数加1的结果
    int mpu_display_Num(int int_param_1)
    {
        return int_param_1 + 1;
    }

    // 带有2个参数的成员函数, 返回成员变量与参数之和
    int mpu_display_Add(int int_param_1, int int_param_2)
    {
        return mpu_Data + int_param_1 + int_param_2;
    }

    // 模板成员函数, 使用折叠表达式求和
    template<typename... Args>
    int mpu_display_Add_many(Args... args)
    {
        return (args + ...);
    }

    int mpu_Data{ 7 };
};

int main() {

    // 设置标准输出为宽字符模式
    _setmode(_fileno(stdout), _O_WTEXT);

    auto class_Mem_Fn = MEM_FN{};

    // 绑定无参数的成员函数, 通过 std::mem_fn 生成可调用对象
    auto fn_display_Str = std::mem_fn(&MEM_FN::mpu_display_Str);
    std::wcout << fn_display_Str(class_Mem_Fn) << std::endl;

    // 绑定带有1个参数的成员函数, 调用时传入类对象和参数
    auto fn_display_Num = std::mem_fn(&MEM_FN::mpu_display_Num);
    std::wcout << fn_display_Num(class_Mem_Fn, 1) << std::endl;

    // 绑定带有2个参数的成员函数, 调用时依次传入类对象和参数
    auto fn_display_Add = std::mem_fn(&MEM_FN::mpu_display_Add);
    std::wcout << fn_display_Add(class_Mem_Fn, 1, 2) << std::endl;

    // 绑定模板成员函数, 注意支持类对象指针传入
    auto pclass_Mem_Fn = std::make_unique<MEM_FN>();
    auto fun_display_Add_many = std::mem_fn(&MEM_FN::mpu_display_Add_many<short, int, long>);
    std::wcout << fun_display_Add_many(pclass_Mem_Fn, 1, 2, 3) << std::endl;

    // 绑定类成员变量, 可直接通过调用获取变量值
    auto fn_access_Data = std::mem_fn(&MEM_FN::mpu_Data);
    std::wcout << fn_access_Data(pclass_Mem_Fn) << std::endl;

    std::cin.get();

    return 0;
}

[代码说明]
1. std::mem_fn绑定成员函数
   通过std::mem_fn可以将成员函数指针转换为可调用对象, 该对象在调用时会自动传入类对象或类对象指针作为第一个参数. 例如, 对于无参函数, 调用时只需传入类对象即可, 对于带参函数, 调用时需要依次传入类对象和相应参数. 与std::bind相比, std::mem_fn不支持占位符等高级绑定功能, 但在简单绑定场景下更为直观和高效.

2. 支持模板成员函数和成员变量的绑定
   利用std::mem_fn绑定模板成员函数mpu_display_Add_many(), 此时需要显式指定模板参数, 同时也利用std::mem_fn直接绑定成员变量mpu_Data. 这种绑定方式既保证了代码的简洁性, 又能提高代码的可读性和性能, 因为不涉及额外的参数转换或包装.

3. 与std::bind的对比
   std::bind提供了更为灵活的参数占位符和参数重排序功能, 适用于复杂绑定需求; 而std::mem_fn则专注于简单, 直接地将成员函数或成员变量转换为可调用对象. 因此, 当仅需简单绑定时, 推荐使用 std::mem_fn以减少额外开销和代码复杂度.

[总结]
std::mem_fn是C++11引入的一个轻量级工具, 专注于将类的成员函数或成员变量转换为可调用的函数对象. 与功能更强大的std::bind相比, 两者在以下几个方面存在显著区别:

1. 设计目标与轻量级特性  
   std::mem_fn专注于绑定类的成员函数和成员变量, 实现简单且高效.
   std::bind是一个通用工具, 不仅能绑定成员函数, 还能处理普通函数、参数占位符和参数重排, 功能更丰富但开销稍大.

2. 使用场景
   如果仅需将成员函数或变量封装为函数对象, std::mem_fn是更直接的选择.  
   若需绑定特定参数值或调整参数顺序, std::bind则更适合.

3. 性能与开销
   std::mem_fn因其单一职责, 在简单场景下通常比std::bind更高效.
   std::bind由于支持复杂功能, 在运行时可能引入额外开销.

4. 代码可读性
   std::mem_fn意图明确, 代码简洁, 适合表达简单的绑定需求.
   std::bind在复杂场景下可能需要更多代码, 可读性稍逊.

在实际开发中, 选择std::mem_fn还是std::bind取决于具体需求. 对于简单的成员函数调用或成员变量访问, std::mem_fn提供了更高的效率和清晰度; 而对于需要参数绑定或更灵活操作的场景, std::bind则是不二之选. 通过理解两者的特点, 可以在现代C++中编写更优雅、更高效的代码.

相关文章:

  • 蓝桥杯嵌入式赛道复习笔记4(TIM输出PWM,TIM输入捕获)
  • Android compose中的附带效应-人话
  • 学习C2CRS Ⅳ (Conversational Recommender Model)
  • IDEA的常用设置与工具集成
  • 玩转python:通俗易懂掌握高级数据结构-collections模块之UserDict
  • 第三:go 操作mysql
  • 在 Visual Studio Code 中高效使用 Pylance:配置、技巧与插件对比
  • 25.3.19(java 数据类型 及数据之间的转换)
  • MySQL 面试题
  • Linux 系统性能调优
  • 【leetcode hot 100 994】腐烂的橘子
  • MongoDB 更新集合名
  • UML(统一建模语言)中总共有哪些图
  • VLLM专题(三十六)—自动前缀缓存
  • 当Anaconda的安装路径与我想创建的conda虚拟环境路径不一致时,应该怎么操作?
  • STM32-汇编
  • 【漫话机器学习系列】143.轮廓系数(Silhouette Coefficient)
  • QT 磁盘文件 教程03-创建、删除、复制文件
  • numpy学习笔记2:ones = np.ones((2, 4)) 的详解
  • PostgreSQL中array_to_string函数来将数组转换成逗号分隔的字符串
  • 手机网站开发相关问题/满十八岁可以申请abc认证吗
  • 网站用什么语言/找文网客服联系方式
  • 室内设计师收入高吗/在线优化seo
  • 网站建网站/开发一个网站的步骤流程
  • 网站 备案/怎么做推广比较成功
  • 网站软件设计/seo知识培训