<functional> 函数对象与函数适配器

<functional> 是 C++ 标准库中的一个头文件,提供了与函数相关的功能,如函数对象(functors)、函数适配器(function adapters)和函数绑定(function binding)。这些工具可以帮助实现更灵活和可重用的代码,尤其在泛型编程中。

1. 函数对象(Functors)

函数对象是重载了 operator() 的类对象。它们可以像普通函数一样被调用,但具有更高的灵活性。

1.1 定义和使用函数对象

#include <iostream>

class Add {
public:
    Add(int x) : x_(x) {}
    int operator()(int y) const {
        return x_ + y;
    }
private:
    int x_;
};

int main() {
    Add add5(5);
    std::cout << "5 + 3 = " << add5(3) << std::endl;  // 输出: 5 + 3 = 8
    return 0;
}

2. std::function

std::function 是一个通用的函数包装器,可以包装任何可调用对象,如普通函数、函数对象、Lambda 表达式、甚至是成员函数。

2.1 使用 std::function

#include <iostream>
#include <functional>

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

int main() {
    std::function<void(int)> func = print;
    func(42);  // 输出: 42
    
    return 0;
}

2.2 使用 Lambda 表达式

#include <iostream>
#include <functional>

int main() {
    std::function<void(int)> func = [](int x) {
        std::cout << x << std::endl;
    };
    func(42);  // 输出: 42
    
    return 0;
}

3. 函数适配器

函数适配器是用于调整函数调用的方式或传递方式的工具。标准库提供了一些常用的函数适配器,如 std::bindstd::not1 / std::not2

3.1 std::bind

std::bind 用于绑定函数参数。它创建一个新的可调用对象,可以将部分参数绑定到原始函数或函数对象上。

#include <iostream>
#include <functional>

void print(int x, int y) {
    std::cout << x << ", " << y << std::endl;
}

int main() {
    auto boundPrint = std::bind(print, 42, std::placeholders::_1);
    boundPrint(24);  // 输出: 42, 24
    
    return 0;
}

3.2 std::not1std::not2

std::not1std::not2 用于取反一个函数对象的结果。注意,这些工具在 C++11 中已经被弃用,被 std::not_fn 替代。

#include <iostream>
#include <functional>

bool isEven(int x) {
    return x % 2 == 0;
}

int main() {
    auto isOdd = std::not_fn(isEven);
    std::cout << std::boolalpha << isOdd(5) << std::endl;  // 输出: true
    
    return 0;
}

4. Lambda 表达式

Lambda 表达式是一种内联的、无名的函数对象,可以用于定义简短的函数体。它们是 C++11 引入的一个强大功能,使得编写匿名函数变得简洁。

4.1 基本用法

#include <iostream>

int main() {
    auto lambda = [](int x) {
        return x * x;
    };
    std::cout << "Square of 5: " << lambda(5) << std::endl;  // 输出: Square of 5: 25
    
    return 0;
}

4.2 捕获外部变量

Lambda 表达式可以捕获外部变量,这些变量可以通过值捕获或引用捕获。

#include <iostream>

int main() {
    int factor = 10;
    auto lambda = [factor](int x) {
        return x * factor;
    };
    std::cout << "10 * 5: " << lambda(5) << std::endl;  // 输出: 10 * 5: 50
    
    return 0;
}

5. 总结

<functional> 提供了多种工具,用于增强函数的灵活性和复用性。函数对象(functors)和 std::function 提供了对函数调用的高级封装,而函数适配器(如 std::bind)和 Lambda 表达式则为函数调用的创建和管理提供了更多的灵活性。这些功能在泛型编程中尤为重要,使得代码更具可重用性和可维护性。