什么网站可以看女人唔易做,六安网络科技股份有限公司,呼市做网站公司,企业展示型网站建设可调用对象包装器, 绑定器
可调用对象
可调用对象是指在 C 中能够像函数一样被调用的实体。它包括了多种类型的对象#xff0c;使得它们能够像函数一样被调用#xff0c;可以是函数、函数指针、函数对象、Lambda 表达式等。在C中#xff0c;具有以下特征之一的实体都被认为…可调用对象包装器, 绑定器
可调用对象
可调用对象是指在 C 中能够像函数一样被调用的实体。它包括了多种类型的对象使得它们能够像函数一样被调用可以是函数、函数指针、函数对象、Lambda 表达式等。在C中具有以下特征之一的实体都被认为是可调用对象
1.函数: 常规的函数包括全局函数和类的成员函数。
void regularFunction(int x) {// ...
}2.函数指针: 指向函数的指针。
#include iostream// 函数原型
void sayHello(const char* name) {std::cout Hello, name ! std::endl;
}int main() {// 定义函数指针并初始化为指向 sayHello 函数void (*helloFunctionPointer)(const char*) sayHello;// 使用函数指针调用函数helloFunctionPointer(Alice);helloFunctionPointer(Bob);return 0;
}3.函数对象: 重载了函数调用运算符 operator() 的类。(仿函数)
#include iostream// 函数对象类
struct Functor {int operator()(int x, int y) {return x y;}
};int main() {// 创建函数对象的实例Functor adder;// 使用函数对象int result adder(3, 4);std::cout Result: result std::endl;return 0;
}4.Lambda表达式: 匿名的函数对象。
#include iostreamint main() {// Lambda 表达式接受一个整数参数并返回它的平方auto square [](int x) {return x * x;};// 调用 Lambda 表达式int result square(5);std::cout Square of 5 is: result std::endl;return 0;
}5.类的成员函数指针: 指向类的成员函数或对象的指针。
#include iostream
#include string
#include vector
using namespace std;struct Test
{void print(int a, string b){cout name: b , age: a endl;}int m_num;
};int main(void)
{// 定义类成员函数指针指向类成员函数void (Test::*func_ptr)(int, string) Test::print;// 类成员指针指向类成员变量int Test::*obj_ptr Test::m_num;Test t;// 通过类成员函数指针调用类成员函数(t.*func_ptr)(19, Monkey D. Luffy);// 通过类成员指针初始化类成员变量t.*obj_ptr 1;cout number is: t.m_num endl;return 0;
}在上面的例子中满足条件的这些可调用对象对应的类型被统称为可调用类型。C中的可调用类型虽然具有比较统一的操作形式但定义方式五花八门这样在我们试图使用统一的方式保存或者传递一个可调用对象时会十分繁琐。现在C11通过提供std::function 和 std::bind统一了可调用对象的各种操作。
可调用对象包装器
std::function是可调用对象的包装器。它是一个类模板可以容纳除了类成员函数指针之外的所有可调用对象。通过指定它的模板参数它可以用统一的方式处理函数、函数对象、函数指针并允许保存和延迟执行它们。
基本用法
std::function必须要包含一个叫做functional的头文件可调用对象包装器使用语法如下:
#include functional
std::function返回值类型(参数类型列表) diy_name 可调用对象;下面的实例代码中演示了可调用对象包装器的基本使用方法
#include iostream
#include functional
using namespace std;int add(int a, int b)
{cout a b a b endl;return a b;
}class T1
{
public:static int sub(int a, int b){cout a - b a - b endl;return a - b;}
};class T2
{
public:int operator()(int a, int b){cout a * b a * b endl;return a * b;}
};int main(void)
{// 绑定一个普通函数functionint(int, int) f1 add;// 绑定以静态类成员函数functionint(int, int) f2 T1::sub;// 绑定一个仿函数T2 t;functionint(int, int) f3 t;// 函数调用f1(9, 3);f2(9, 3);f3(9, 3);return 0;
}输入结果如下:
9 3 12
9 - 3 6
9 * 3 27通过测试代码可以得到结论std::function可以将可调用对象进行包装得到一个统一的格式包装完成得到的对象相当于一个函数指针和函数指针的使用方式相同通过包装器对象就可以完成对包装的函数的调用了。
作为回调函数使用
因为回调函数本身就是通过函数指针实现的使用对象包装器可以取代函数指针的作用来看一下下面的例子
#include iostream
#include functional
using namespace std;// 模拟某个异步操作
void performAsyncOperation(functionvoid() callback) {// 模拟异步操作完成后调用回调函数std::cout Async operation completed. std::endl;callback();
}// 回调函数1
void callback1() {std::cout Callback 1 called. std::endl;
}// 回调函数2
void callback2() {std::cout Callback 2 called. std::endl;
}int main() {// 使用 function 作为回调函数的容器functionvoid() callbackFunc1 callback1;functionvoid() callbackFunc2 callback2;// 执行异步操作传递回调函数performAsyncOperation(callbackFunc1);// 执行异步操作传递另一个回调函数performAsyncOperation(callbackFunc2);return 0;
}在这个例子中CallbackFunction 是一个 std::function 类型用于表示无返回值且无参数的回调函数。performAsyncOperation 函数模拟了一个异步操作完成后调用传递的回调函数。在 main 函数中创建了两个不同的回调函数然后分别传递给 performAsyncOperation 函数。
绑定器
std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存并延迟调用到任何我们需要的时候。通俗来讲它主要有两大作用
将可调用对象与其参数一起绑定成一个仿函数。将多元参数个数为nn1可调用对象转换为一元或者n-1元可调用对象即只绑定部分参数。
绑定器函数使用语法格式如下
// 绑定非类成员函数/变量
auto f std::bind(可调用对象地址, 绑定的参数/占位符);
// 绑定类成员函/变量
auto f std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);先来看两个简单例子:
#include functional
#include iostreamvoid functionToBind(int a, int b) {std::cout Sum: a b std::endl;
}int main() {// 使用 std::bind 绑定函数和参数auto boundFunction std::bind(functionToBind, 10, std::placeholders::_1);// 调用绑定的函数boundFunction(20); // 输出 Sum: 30return 0;
}在这个例子中std::bind 绑定了 functionToBind 函数并将第一个参数绑定为 10第二个参数使用 std::placeholders::_1 占位符表示稍后提供的参数。然后通过调用 boundFunction(20)实际提供了一个参数 20而 std::placeholders::_1 被替换为 20最终调用了 functionToBind(10, 20)。
#include functional
#include iostreamclass MyClass {
public:void memberFunction(int a, int b) {std::cout Sum: a b std::endl;}
};int main() {MyClass obj;// 使用 std::bind 绑定成员函数和对象auto boundMemberFunction std::bind(MyClass::memberFunction, obj, 10, std::placeholders::_1);// 调用绑定的成员函数boundMemberFunction(20); // 输出 Sum: 30return 0;
}这个例子演示了如何使用 std::bind 绑定类的成员函数。注意需要提供对象的地址作为第一个参数 , obj 为第二个参数。后续的参数和占位符的使用方式与前面的例子类似。
在上面的程序中使用了std::bind绑定器在函数外部通过绑定不同的函数控制了最后执行的结果。std::bind绑定器返回的是一个仿函数类型得到的返回值可以直接赋值给一个std::function在使用的时候我们并不需要关心绑定器的返回值类型使用auto进行自动类型推导就可以了。
placeholders::_1是一个占位符代表这个位置将在函数调用时被传入的第一个参数所替代。同样还有其他的占位符placeholders::_2、placeholders::_3、placeholders::_4、placeholders::_5等……
有了占位符的概念之后使得std::bind的使用变得非常灵活:
#include iostream
#include functional
using namespace std;void output(int x, int y)
{cout x y endl;
}int main(void)
{// 使用绑定器绑定可调用对象和参数, 并调用得到的仿函数bind(output, 1, 2)();bind(output, placeholders::_1, 2)(10);bind(output, 2, placeholders::_1)(10);// error, 调用时没有第二个参数// bind(output, 2, placeholders::_2)(10);// 调用时第一个参数10被吞掉了没有被使用bind(output, 2, placeholders::_2)(10, 20);functionvoid(int, int) func1 bind(output, placeholders::_1, placeholders::_2);auto func2 bind(output, placeholders::_2, placeholders::_1);func1(10, 20);func2(10, 20);return 0;
}示例代码执行的结果:
1 2 // bind(output, 1, 2)();
10 2 // bind(output, placeholders::_1, 2)(10);
2 10 // bind(output, 2, placeholders::_1)(10);
2 20 // bind(output, 2, placeholders::_2)(10, 20);
10 20 // bind(output, placeholders::_1, placeholders::_2)(10, 20);
20 10 // bind(output, placeholders::_2, placeholders::_1)(10, 20);通过测试可以看到std::bind可以直接绑定函数的所有参数也可以仅绑定部分参数。在绑定部分参数的时候通过使用std::placeholders来决定空位参数将会属于调用发生时的第几个参数。
可调用对象包装器std::function是不能实现对类成员函数指针或者类成员指针的包装的但是通过绑定器std::bind的配合之后就可以完美的解决这个问题了再来看一个例子然后再解释里边的细节
#include iostream
#include functional
using namespace std;class Test
{
public:void output(int x, int y){cout x: x , y: y endl;}int m_number 100;
};int main(void)
{Test t;// 绑定类成员函数functionvoid(int, int) f1 bind(Test::output, t, placeholders::_1, placeholders::_2);// 绑定类成员变量(公共)functionint(void) f2 bind(Test::m_number, t);// 调用f1(520, 1314);f2() 2333;cout t.m_number: t.m_number endl;return 0;
}示例代码输出的结果:
x: 520, y: 1314
t.m_number: 2333在用绑定器绑定类成员函数或者成员变量的时候需要将它们所属的实例对象一并传递到绑定器函数内部。f1的类型是functionvoid(int, int)通过使用std::bind将Test的成员函数output的地址和对象t绑定并转化为一个仿函数并存储到对象f1中。
使用绑定器绑定的类成员变量m_number得到的仿函数被存储到了类型为functionint(void)的包装器对象f2中并且可以在需要的时候修改这个成员。其中int是绑定的类成员的类型并且允许修改绑定的变量因此需要指定为变量的引用由于没有参数因此参数列表指定为void。
示例程序中是使用function包装器保存了bind返回的仿函数如果不知道包装器的模板类型如何指定可以直接使用auto进行类型的自动推导这样使用起来会更容易一些。