背景
在C++98及之前的标准中,处理函数指针和回调函数时常常会遇到类型不匹配、灵活性差等问题。为了解决这些问题,C++11引入了function,它是一个通用的多态函数包装器,能够存储、复制及调用任何可调用目标(Callable target)——函数、lambda表达式、绑定表达式(bind expression)以及其他函数对象,并可以作为它们的通用类型。
function
function 是一个模板类,它可以存储、复制、以及调用任何可以调用的目标(Callable),比如函数、Lambda表达式、函数对象、以及绑定表达式等。它提供了一种通用的方式来处理这些可调用对象,使得函数式编程和回调机制在C++中变得更加容易和灵活。
作用
1.提供了一种类型安全的封装来存储和调用可调用对象。
2.增强了代码的灵活性和可重用性。
3.使得函数指针、Lambda表达式等可以统一处理。
用法
#include <iostream>
#include <functional>
// 一个普通的函数
int add(int x, int y) {
return x + y;
}
int main() {
// 使用std::function来封装一个函数指针
std::function<int(int, int)> funcPtr = add;
// 使用std::function来封装一个Lambda表达式
std::function<int(int, int)> lambdaFunc = [](int x, int y) { return x * y; };
// 调用
std::cout << "Function pointer: " << funcPtr(2, 3) << std::endl; // 输出 5
std::cout << "Lambda expression: " << lambdaFunc(2, 3) << std::endl; // 输出 6
return 0;
}
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
cout << useF(f, 11.11) << endl;
// 函数对象
cout << useF(Functor(), 11.11) << endl;
// lamber表达式
cout << useF([](double d)->double{ return d/4; }, 11.11) << endl;
return 0;
}
上面的代码useF函数模板实例化了三份。
我们能利用function包装器优化
#include <functional>
template<class F, class T>
T useF(F f, T x)
{
static int count = 0;
cout << "count:" << ++count << endl;
cout << "count:" << &count << endl;
return f(x);
}
double f(double i)
{
return i / 2;
}
struct Functor
{
double operator()(double d)
{
return d / 3;
}
};
int main()
{
// 函数名
std::function<double(double)> func1 = f;
cout << useF(func1, 11.11) << endl;
// 函数对象
std::function<double(double)> func2 = Functor();
cout << useF(func2, 11.11) << endl;
// lamber表达式
std::function<double(double)> func3 = [](double d)->double{ return d /
4; };
cout << useF(func3, 11.11) << endl;
return 0;
}
bind
bind 是一个函数模板,用于创建一个新的可调用实体(function object),该实体将给定的可调用对象(比如函数、Lambda表达式、函数对象等)与其参数进行绑定。这允许我们预先设置函数的某些参数,然后创建一个新的函数对象,这个新的函数对象在被调用时,会自动将预先设置的参数传递给原始的可调用对象。
作用
允许我们预先绑定函数的参数。
创建具有部分参数已固定的新函数对象。
在回调机制中非常有用,尤其是当回调函数需要额外信息时。
用法
#include <iostream>
#include <functional>
// 一个接受三个参数的函数
void print(int x, int y, int z) {
std::cout << "x: " << x << ", y: " << y << ", z: " << z << std::endl;
}
int main() {
// 使用std::bind绑定前两个参数
auto boundFunc = std::bind(print, std::placeholders::_1, 10, std::placeholders::_2);
// 调用时,只需要提供剩余的两个参数
boundFunc(20, 30); // 输出: x: 20, y: 10, z: 30
// 也可以使用Lambda表达式来达到类似的效果,但std::bind在某些情况下更加直观
return 0;
}
在上面的例子中,std::placeholders::_1 和 std::placeholders::_2 是占位符,用于表示在调用 boundFunc 时需要提供的参数。在这个例子中,boundFunc 被创建为一个新的可调用对象,它预先绑定了 print 函数的第二个参数为 10,因此当调用 boundFunc(20, 30) 时,实际上是在调用 print(20, 10, 30)。