通过手撕std::bind来了解其工作原理

std::bind 是 C++11 中的一个函数模板,用于创建一个可调用对象(函数对象或者函数指针)的绑定副本,其中一部分参数被固定为指定值,从而生成一个新的可调用对象。

std::bind 的原理可以简单概括如下:

  1. 创建绑定副本:

    当调用 std::bind 时,会生成一个新的可调用对象,其中一部分参数被绑定为指定值,剩余的参数保留为占位符(placeholder)。

  2. 占位符:

    std::bind 中,占位符使用 _1, _2, _3 等进行表示,分别代表可调用对象的第一个、第二个、第三个参数,以此类推。在创建绑定副本时,可以通过占位符指定参数的位置。

  3. 生成新的可调用对象:

    绑定副本可以作为一个新的可调用对象,可以直接调用,也可以传递给其他接受可调用对象的函数,从而实现部分参数固定的函数调用。

  4. 参数传递:

    在调用绑定副本时,传递给绑定副本的参数会替换掉占位符,从而形成最终的参数列表,并调用原始函数或函数对象。

  5. 绑定对象的生命周期:

    绑定副本会对传递给它的参数进行复制或者引用,因此绑定对象中的参数需要在绑定副本被调用时仍然有效。

以下是 std::bind 的一个简单示例:

cpp 复制代码
#include <iostream>
#include <functional>

void print_sum(int a, int b) {
    std::cout << a + b << std::endl;
}

int main() {
    auto f = std::bind(print_sum, 10, std::placeholders::_1);
    f(20); // 输出 30
    return 0;
}

在这个示例中,std::bind 生成了一个新的可调用对象 f,其中 print_sum 函数的第一个参数被绑定为 10,而第二个参数被保留为占位符 _1。当调用 f(20) 时,20 会替换占位符 _1,从而调用 print_sum(10, 20),输出 30。

下面,我们来实现一个简化版的std::bind,以更加深入的了解std::bind的工作原理:

cpp 复制代码
#include <iostream>
#include <functional>

// 定义一个模板类 MyBind,用于实现类似 std::bind 的功能
template <typename Func, typename... Args>
class MyBind {
public:
    // 构造函数,接受一个函数对象和一系列参数,这里需要用&&,以实现完美转发
    MyBind(Func&& func, Args&&... args)
        : func_(std::forward<Func>(func)), args_(std::forward<Args>(args)...) {}

    // 重载 () 运算符,用于调用绑定的函数对象
    template <typename... OtherArgs>
    auto operator()(OtherArgs&&... other_args) {
        // 调用 call_func 函数,将传递给它的参数与绑定的参数一起传递给原始函数对象
        return call_func(std::index_sequence_for<Args...>(), std::forward<OtherArgs>(other_args)...);
    }

private:
    // call_func 函数用于将传递给它的参数与绑定的参数一起传递给原始函数对象
    template <size_t... I, typename... OtherArgs>
    auto call_func(std::index_sequence<I...>, OtherArgs&&... other_args) {
        // 调用原始函数对象,传递绑定的参数和其他参数
        return func_(std::get<I>(args_)..., std::forward<OtherArgs>(other_args)...);
    }

    Func func_;                         // 原始的函数对象
    std::tuple<Args...> args_;          // 绑定的参数
};

// 辅助函数,用于创建 MyBind 对象
template <typename Func, typename... Args>
MyBind<Func, Args...> my_bind(Func&& func, Args&&... args) {
    return MyBind<Func, Args...>(std::forward<Func>(func), std::forward<Args>(args)...);
}

// 测试函数
void print_sum(int a, int b) {
    std::cout << a + b << std::endl;
}

int main() {
    auto f = my_bind(print_sum, 10, std::placeholders::_1); // 创建 MyBind 对象 f,绑定 print_sum 函数和参数
    f(20); // 调用绑定对象 f,传递参数 20,输出 30
    return 0;
}
相关推荐
Sally璐璐12 分钟前
IPSAN 共享存储详解:架构、优化与落地实践指南
开发语言·php
Mr.Winter`18 分钟前
轨迹优化 | 基于激光雷达的欧氏距离场ESDF地图构建(附ROS C++仿真)
c++·人工智能·机器人·自动驾驶·ros·ros2·具身智能
csdn_aspnet20 分钟前
C++ n条水平平行线与m条垂直平行线相交的平行四边形的数量
c++
像风一样的男人@22 分钟前
python --货车装厢问题
开发语言·python
Humbunklung29 分钟前
Rust枚举:让数据类型告别单调乏味
开发语言·后端·rust
Y1nhl32 分钟前
力扣_链表_python版本
开发语言·python·算法·leetcode·链表·职场和发展
OEC小胖胖1 小时前
深入理解 Vue.js 响应式原理及其在 Web 前端开发中的应用
开发语言·前端·javascript·vue.js·web
qq_401700411 小时前
C语言中位运算以及获取低8位和高8位、高低位合并
c语言·开发语言·算法
yanjiaweiya1 小时前
云原生-集群管理
java·开发语言·云原生
闻缺陷则喜何志丹1 小时前
【BFS】 P10864 [HBCPC2024] Genshin Impact Startup Forbidden II|普及+
c++·算法·宽度优先·洛谷