C++11的新特性:四、std::function与std::bind

在 C++ 编程中,std::function 和 std::bind 是 C++11 引入的两个非常实用的特性,它们为处理可调用对象提供了极大的便利,能有效提升代码的灵活性和可维护性。下面我们就来深入探讨这两个知识点。

(一)可调用对象的多种形式

在 C++ 中,可调用对象(Callable Objects)是一个很重要的概念,主要有以下几种形式:

1.函数指针:这是最传统的可调用对象形式。例如:

void func(int x) 
{
    std::cout << "func(int x): " << x << std::endl;
}

这里的 func 就是一个函数指针类型的可调用对象。


2. 具有 operator() 的类对象(仿函数):通过定义类的 operator(),可以让类对象像函数一样被调用。

struct Foo 
{
    void operator()(int x) 
    {
        std::cout << "Foo::operator()(int x): " << x << std::endl;
    }
};

Foo 类的对象就是仿函数类型的可调用对象。

3. 可转换为函数指针的类对象:有些类可以定义转换函数,使其能够转换为函数指针,从而作为可调用对象使用。
4. 类成员函数指针:指向类成员函数的指针也是可调用对象,调用时需要通过类对象或类指针来进行。

(二)std::function:可调用对象的统一包装器

std::function 是一个可调用对象的包装器,它是一个模板类,能够存储除了类成员指针之外的所有可调用对象。通过指定它的模板参数,可以用统一的方式处理函数、函数对象、函数指针等。

1. 基本使用示例

#include 
#include 

void func(int x) 
{
    std::cout << "func name: " << __FUNCTION__ << ", x: " << x << std::endl;
}

class Foo 
{
public:
    static int func(int x) 
    {
        std::cout << "func name: " << __FUNCTION__ << ", x: " << x << std::endl;
        return x;
    }
};

class Bar 
{
public:
    void operator()(int x) 
    {
        std::cout << "func name: " << __FUNCTION__ << ", x: " << x << std::endl;
    }
};

int main() 
{
    int x = 10;
    // 包装普通函数
    std::function f1 = func;
    f1(x);

    // 包装类的静态成员函数
    std::function f2 = Foo::func;
    std::cout << f2(x) << std::endl;

    Bar bar;
    // 包装仿函数
    std::function f3 = bar;
    f3(x);

    return 0;
}

在这个示例中,std::function 分别包装了普通函数、类的静态成员函数和仿函数,使得它们可以以统一的方式被调用。

2. 作为回调函数使用

std::function 常用于实现回调机制。例如:

#include 
using namespace std;

class A 
{
public:
    std::function callback;
    void call_back(const std::function& f) 
    {
        callback = f;
    }
    void execute() 
    {
        if (callback) 
        {
            callback();
        }
    }
};

class Foo 
{
public:
    void operator()() 
    {
        std::cout << __FUNCTION__ << std::endl;
    }
};

int main() 
{
    A a;
    Foo foo;
    a.call_back(foo);
    a.execute();

    return 0;
}

这里,A 类通过 std::function 存储回调函数,在合适的时候调用它,使得代码的扩展性和灵活性大大增强。

(三)std::bind:可调用对象的绑定器

std::bind 用于将可调用对象与其参数一起进行绑定,绑定后的结果可以使用 std::function 进行保存,并延迟调用。它主要有两大作用:

1.绑定参数:将可调用对象与某些参数绑定成一个新的可调用对象。

#include 
#include 

void output(int x) 
{
    std::cout << x << std::endl;
}

int main() 
{
    // 将output函数的参数绑定为10
    auto f = std::bind(output, 10);
    f();

    return 0;
}

在这个例子中,std::bind 将 output 函数的参数绑定为 10,调用 f() 时就相当于调用 output(10)
2. 调整参数个数和顺序:将多元(参数个数为 n, n>1)可调用对象转换为一元(参数个数为 1)可调用对象,或者调整部分参数的顺序。

#include 
#include 

void add(int x, int y) 
{
    std::cout << x + y << std::endl;
}

int main() 
{
    // 将add函数的第一个参数绑定为5
    auto f1 = std::bind(add, 5, std::placeholders::_1);
    f1(3); // 相当于调用add(5, 3)

    // 交换add函数参数的顺序
    auto f2 = std::bind(add, std::placeholders::_2, std::placeholders::_1);
    f2(2, 4); // 相当于调用add(4, 2)

    return 0;
}

这里使用了 std::placeholders::_n 作为占位符,n 表示在调用新的可调用对象时,该位置的参数将由第 n 个传入的参数替代。

(四)结合使用 std::function 和 std::bind

在实际编程中,std::function 和 std::bind 经常结合使用,这样可以更灵活地处理各种可调用对象。

#include 
#include 

void call_when_event(int x, const std::function& f) 
{
    if (x % 2 == 0) 
    {
        f(x);
    }
}

void output(int x) 
{
    std::cout << x << std::endl;
}

int main() 
{
    for (int i = 0; i < 10; ++i) 
    {
        auto f = std::bind(output, i);
        call_when_event(i, f);
    }

    return 0;
}

在这个例子中,通过 std::bind 绑定 output 函数的参数,再将其作为回调函数传递给 call_when_event 函数,只有当满足特定条件时,绑定后的函数才会被调用。

std::function 和 std::bind 为 C++ 开发者提供了强大而灵活的工具,通过统一处理可调用对象和灵活绑定参数,能够让代码更加简洁、易读,并且具有更好的扩展性和维护性 。

你可能感兴趣的:(C++11新特性,c++,开发语言)