商城首页欢迎来到中国正版软件门户

您的位置:首页 >C++11包装器function和bind示例详解

C++11包装器function和bind示例详解

  发布于2026-05-20 阅读(0)

扫一扫,手机访问

包装器

在C++的现代编程实践中,我们常常会遇到一个挑战:如何统一地处理不同类型的可调用对象?比如,你有一个普通函数、一个仿函数、一个lambda表达式,甚至是一个类的成员函数。它们功能相似,但类型各异,直接放在一起管理会非常麻烦。这时候,std::function 就该登场了。

std::function:可调用对象的通用“接口”

简单来说,std::function 是一个类模板,它的核心使命就是“统一类型”。它能把各种形态的可调用对象包装起来,让它们穿上统一的“外衣”,从而实现多态调用。你可以把它想象成一个万能的函数指针,但功能要强大得多。

它的基本格式是 std::function<返回值类型(参数类型列表)>。这个模板实例化出来的对象,就可以用来存储(或者说“包装”)一个目标可调用对象。如果这个 std::function 对象内部没有存储任何目标,那它就是“空”的,调用一个空的 std::function 会抛出 std::bad_function_call 异常。

来看看它能包装些什么:

int add(int a, int b) { return a + b; } // 普通函数

struct Mul {
    int operator()(int a, int b) { return a * b; }
}; // 仿函数

class MyClass{
public:
    static int s_add(int a,int b){
        return a+b;
    }
    int add(int a,int b){
        return a+b;
    }
};

int main() {
    function f; // 创建一个空的 std::function

    f = add; // 包装普通函数
    f = Mul(); // 包装仿函数对象
    f = [](int a, int b) { return a - b; }; // 包装 lambda 表达式

    f = &MyClass::s_add; // 包装静态成员函数,需要取地址并指明类域

    // 包装普通成员函数有点特殊,因为需要传递 this 指针。
    // 在 std::function 的模板参数中,需要显式写出接收对象的类型。
    function c_f; // 按值传递对象
    function p_f; // 按指针传递对象
    c_f = &MyClass::add;
    p_f = &MyClass::add;

    // 调用时,需要将对应的对象实例传进去
    MyClass mc;
    cout << c_f(mc, 1, 1) << endl; // 传递对象
    cout << p_f(&mc, 1, 1) << endl; // 传递对象地址

    function empty_func;
    // empty_func(); // 错误!不能调用空的目标
    return 0;
}

可以看到,无论是哪种形式,最终我们都能通过统一的 f 对象来调用,这就是它的威力所在。

bind:函数的“变形器”

如果说 std::function 解决了“类型统一”的问题,那么 std::bind 则擅长解决“参数适配”的问题。它也是一个函数模板,可以看作是一个可调用对象的“加工厂”。

bind 接收一个原始的可调用对象 fn 和一个参数列表 arg_list,然后返回一个新的可调用对象。这个新对象的神奇之处在于,你可以重新安排、固定甚至减少原始调用所需要的参数。它的常见用法是:auto newFunc = bind(func, arg_list);

这里的关键在于理解 arg_list。它并不是直接传递的参数值列表,而是定义了新函数 newFunc 的参数如何映射到原函数 func 的参数上。占位符 _1, _2, _3...(位于 std::placeholders 命名空间)代表 newFunc 的第1、2、3...个参数。如果不使用占位符,而是直接写入一个值,那么这个参数就被“固定”住了。

void func(int a, int b)
{
    cout << a << " " << b << endl;
}
int main()
{
    using namespace std::placeholders; // 使用占位符

    // 1. 调整参数顺序:将 newfunc1 的第2个参数给 func 的第1个位置,第1个参数给 func 的第2个位置
    auto newfunc1 = bind(func, _2, _1);
    newfunc1(10, 20); // 实际调用 func(20, 10),输出:20 10

    // 2. 固定部分参数:将 func 的第一个参数固定为 100
    auto newfunc2 = bind(func, 100, _1);
    newfunc2(200);    // 实际调用 func(100, 200),输出:100 200

    // 3. 减少参数数量:将 func 的两个参数全部固定
    auto newfunc3 = bind(func, 66, 88);
    newfunc3();       // 实际调用 func(66, 88),输出:66 88
}

通过 bind,我们可以非常灵活地生成适配不同接口的新函数对象,再结合 std::function 进行统一管理,这在设计回调机制、事件系统时尤其有用。两者联手,为C++的函数式编程风格提供了强大的基础设施。

本文转载于:https://www.jb51.net/program/363920z71.htm 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注