function 和 bind 是C++11标准从boost库引入到std中的。
1. function 包装器
function是一种函数包装器,也叫做适配器。它可以对可调用对象进行包装,C++中的function本质就是一个类模板。
函数原型:
template <class T> function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
参数:
- Ret : 调用函数返回值的类型
- Args :任意数量和类型的模板参数包
1.1 包装示例
function包装器可以对可调用对象进行包装,包括函数指针(函数名)、仿函数(函数对象)、lambda表达式、类的成员函数。比如:
#include <iostream>
#include <functional>
//function包装器可以对可调用对象进行包装,包括函数指针(函数名)、仿函数(函数对象)、lambda表达式、类的成员函数
int func1(int x, int y)
{
return x + y;
}
//仿函数
struct func2
{
int operator()(int x,int y)
{
return x + y;
}
};
struct MyStruct
{
int m_value;
int func3(int x)
{
return x + m_value;
}
};
int main()
{
//包装函数
std::function<int(int, int)> fn1 = func1;
//包装函数指针
std::function<int(int, int)> fn2 = &func1;
//包装仿函数
std::function<int(int, int)> fn3 = func2();
//包装lambda
std::function<int(int, int)> fn4 = [](int x, int y) {
return x + y;
};
//包装类的成员函数
std::function<int(MyStruct&,int)> fn5 = &MyStruct::func3;
//包装类的成员变量
std::function<int(MyStruct&)> fn6 = &MyStruct::m_value;
std::cout << fn1(1, 2) << std::endl;
std::cout << fn2(1, 2) << std::endl;
std::cout << fn3(1, 2) << std::endl;
std::cout << fn4(1, 2) << std::endl;
MyStruct ms{1};
std::cout << fn5(ms,2) << std::endl;
std::cout << fn6(ms) << std::endl;
return 0;
}
- 包装时指明返回值类型和各形参类型,然后将可调用对象赋值给function包装器即可,包装后function对象就可以像普通函数一样使用了。
- 包装非静态的成员函数时需要注意,非静态成员函数的第一个参数是隐藏this指针,因此在包装时需要指明第一个形参的类型为类的类型。
1.2 function 统一类型
#include <iostream>
#include <functional>
template<class F, class T>
T test1(F func, T t)
{
static int value = 0;
std::cout << "valude =" << ++value << std::endl;
std::cout << "&valude =" << &value << std::endl;
return func(t);
}
int test2(int x)
{
return x;
}
struct Test3
{
int operator()(int x)
{
return x;
}
};
int main()
{
std::cout << test1(test2, 6) << std::endl;
std::cout << test1(Test3(), 66) << std::endl;
std::cout << test1([](int x)->int {return x; }, 666) << std::endl;
}
运行结果:
由于函数指针、仿函数、lambda表达式是不同的类型,因此test1函数会被实例化出三份,三次调用test1函数所打印value的地址也是不同的。
这时就可以用function包装器分别对这三个可调用对象进行包装,然后再用这三个包装后的可调用对象来调用test1函数, 如下:
#include <iostream>
#include <functional>
template<class F, class T>
T test1(F func, T t)
{
static int value = 0;
std::cout << "valude =" << ++value << std::endl;
std::cout << "&valude =" << &value << std::endl;
return func(t);
}
int test2(int x)
{
return x;
}
struct Test3
{
int operator()(int x)
{
return x;
}
};
int main()
{
std::function<int(int)> fn1 = test2;
std::function<int(int)> fn2 = Test3();
std::function<int(int)> fn3 = [](int x)->int {return x; };
std::cout << test1(fn1, 6) << std::endl;
std::cout << test1(fn2, 66) << std::endl;
std::cout << test1(fn3, 666) << std::endl;
}
运行结果:
这时就只会实例化出一份test1函数。
1.3 function包装器的意义
- 将可调用对象的类型进行统一,便于我们对其进行统一化管理。
- 包装后明确了可调用对象的返回值和形参类型,更加方便使用者使用。
2. bind
bind和function都是包装器,bind的用途是绑定固定的参数,在调用时可以不用传递某些参数。
函数原型:
template <class Fn, class... Args>
bind(Fn&& fn, Args&&... args);
template <class Ret, class Fn, class... Args>
bind(Fn&& fn, Args&&... args);
参数:
- fn: 函数对象、函数指针或类的成员函数。
- args: 要绑定的参数列表:值或占位符
- 占位符就是占着位置,不起实际作用,用的时候传递参数即可
2.1 使用示例
绑定普通函数
#include <iostream>
#include <functional>
double func(double x, double y)
{
return x / y;
}
int main()
{
//bind函数
auto fn1 = std::bind(func, 10, 2);
std::cout << fn1() << std::endl;
//带占位符
auto fn2 = std::bind(func, std::placeholders::_1, 2); //return x/2
std::cout << fn2(10) << std::endl; // 5
auto fn3 = std::bind(func, std::placeholders::_1, std::placeholders::_2); // return x / y
std::cout << fn3(10,2) << std::endl; // 5
auto fn4 = std::bind(func, std::placeholders::_2, std::placeholders::_1); //return y / x
std::cout << fn4(10,2) << std::endl; //0.2
//带返回值类型
auto fn5 = std::bind<int>(func, std::placeholders::_2, std::placeholders::_1); //return (int)(y/x)
std::cout << fn5(10, 2) << std::endl; // 0
}
绑定类的成员对象
#include <iostream>
#include <functional>
class Calculator {
public:
int add_sum(int a, int b)
{
return a + b;
}
};
int main() {
Calculator calcu;
Calculator& ref_calcu = calcu;
Calculator* prt_calcu = &calcu;
std::function<int(int)> func1 = std::bind<int>(&Calculator::add_sum, calcu, std::placeholders::_1, 20); //return Calculator().add_sum(x,20);/
std::function<int(int)> func2 = std::bind<int>(&Calculator::add_sum, ref_calcu, std::placeholders::_1, 20); //return Calculator().add_sum(x,20);
std::function<int(int)> func3 = std::bind<int>(&Calculator::add_sum, prt_calcu, std::placeholders::_1, 20); //return Calculator().add_sum(x,20)
std::cout << func1(10) << std::endl; //30
std::cout << func2(10) << std::endl; //30
std::cout << func3(10) << std::endl; //30
return 0;
}
绑定成员函数时,需要传递对象或对象指针或引用