可调用对象
案例
#include <iostream>
#include <string>
#include <vector>
using namespace std;
using funcptr = void(*)(int, string);
int print(int a, double b)
{
cout << a << ", " << b << endl;
return 0;
}
// 定义函数指针
int (*func)(int, double) = &print;
struct Test
{
int m_id;
// ()操作符重载
void operator()(string msg)
{
cout << "msg: " << msg << endl;
}
//属于类的
static void world(int a, string b)
{
cout << "name: " << b << ", age: " << a << endl;
}
//属于对象
void hello(int a, string b)
{
cout << "name: " << b << ", age: " << a << endl;
}
// 将类对象转换为函数指针 ----> 指定world被调用
operator funcptr()
{
//return hello;//err
return world;
}
};
int main(void)
{
func(1, 2);
Test t;
t("hello world");
Test tt;
// 对象转换为函数指针, 并调用
tt(19, "Monkey D. Luffy");
//-----------------------------------------------------------------------------
//类的函数指针
//左侧是不属于类的函数指针,右侧是属于类的函数指针
//funcptr f = Test::hello;//err
//函数名就是地址 下面两个写法都对
funcptr f1 = Test::world;
f1(10, "冬狮郎");
funcptr f2 = &Test::world;
f2(0, "黑崎一护");
using fptr = void(Test::*)(int, string);
fptr f3 = &Test::hello;
Test ttt;
(ttt.*f3)(2, "碎蜂");
//---------------------------------------------------------------
//类的成员指针(变量)
using ptr1 = int Test::*;
ptr1 pt = &Test::m_id;
ttt.*pt = 1008611;
cout << "m_id:" << ttt.m_id << endl;
return 0;
}
可调用对象包装器
std::function是可调用对象的包装器。它是一个类模板
,可以容纳除了类(非静态)成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟执行它们。
语法
#include <functional>
std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;
案例
#include <iostream>
#include <string>
#include <vector>
#include <functional>
using namespace std;
using funcptr = void(*)(int, string);
int print(int a, double b)
{
cout << a << ", " << b << endl;
return 0;
}
// 定义函数指针
int (*func)(int, double) = &print;
struct Test
{
int m_id;
// ()操作符重载 >>> 仿函数
void operator()(string msg)
{
cout << "msg: " << msg << endl;
}
//属于类的
static void world(int a, string b)
{
cout << "name: " << b << ", age: " << a << endl;
}
//属于对象
void hello(int a, string b)
{
cout << "name: " << b << ", age: " << a << endl;
}
// 将类对象转换为函数指针 ----> 指定world被调用
operator funcptr()
{
//return hello;//err
return world;
}
};
int main(void)
{
//1、函数指针
func(1, 2.2);
//2、仿函数
Test t;
t("hello world");
Test tt;
//对象转换为函数指针, 并调用 >>>>>>>>>>>>>>>>>>>> operator 对应函数
tt(19, "Monkey D. Luffy");
//3、类的函数指针
//左侧是不属于类的函数指针,右侧是属于类的函数指针
//funcptr f = Test::hello;//err
//函数名就是地址 下面两个写法都对
funcptr f1 = Test::world;
f1(10, "冬狮郎");
funcptr f2 = &Test::world;
f2(0, "黑崎一护");
using fptr = void(Test::*)(int, string);
fptr f3 = &Test::hello;
Test ttt;
(ttt.*f3)(2, "碎蜂");
//4、类的成员指针(变量)
using ptr1 = int Test::*;
ptr1 pt = &Test::m_id;
ttt.*pt = 1008611;
cout << "m_id:" << ttt.m_id << endl;
//*********************************************************************************************
cout << endl << endl << endl;
//*********************************************************************************************
//1、包装普通函数
function<void(int, double)>f4 = print;
f4(1, 2.2);
//2、包装静态函数
function<void(int, string)>f5 = Test::world;
f5(5, "蓝染");
//3、包装仿函数
Test ta;
function<void(string)>f6 = ta;
f6("浦原喜助");
//4、包装转换为函数指针的对象
Test tb;
function<void(int, string)>f7 = tb;
f7(11, "更木剑八");
return 0;
}
可调用对象包装器作为函数参数
#include <iostream>
#include <string>
#include <vector>
#include <functional>
using namespace std;
using funcptr = void(*)(int, string);
int print(int a, double b)
{
cout << a << ", " << b << endl;
return 0;
}
// 定义函数指针
int (*func)(int, double) = &print;
struct Test
{
int m_id;
// ()操作符重载 >>> 仿函数
void operator()(string msg)
{
cout << "msg: " << msg << endl;
}
//属于类的
static void world(int a, string b)
{
cout << "name: " << b << ", age: " << a << endl;
}
//属于对象
void hello(int a, string b)
{
cout << "name: " << b << ", age: " << a << endl;
}
// 将类对象转换为函数指针 ----> 指定world被调用
operator funcptr()
{
//return hello;//err
return world;
}
};
class A
{
public:
// 构造函数参数是一个包装器对象
A(const function<void(int,string)>& f) : callback(f)
{
}
void notify(int id, string name)
{
callback(id, name); // 调用通过构造函数得到的函数指针
}
private:
function<void(int,string)> callback;
};
int main(void)
{
//1、函数指针
func(1, 2.2);
//2、仿函数
Test t;
t("hello world");
//2.5、是一个可被转换为函数指针的类对象
Test tt;
//对象转换为函数指针, 并调用 >>>>>>>>>>>>>>>>>>>> operator 对应函数
tt(19, "Monkey D. Luffy");
//3、类的函数指针
//左侧是不属于类的函数指针,右侧是属于类的函数指针
//funcptr f = Test::hello;//err
//函数名就是地址 下面两个写法都对
funcptr f1 = Test::world;
f1(10, "冬狮郎");
funcptr f2 = &Test::world;
f2(0, "黑崎一护");
using fptr = void(Test::*)(int, string);
fptr f3 = &Test::hello;
Test ttt;
(ttt.*f3)(2, "碎蜂");
//4、类的成员指针(变量)
using ptr1 = int Test::*;
ptr1 pt = &Test::m_id;
ttt.*pt = 1008611;
cout << "m_id:" << ttt.m_id << endl;
//*********************************************************************************************
cout << endl << endl;
//*********************************************************************************************
//1、包装普通函数
function<void(int, double)>f4 = print;
f4(1, 2.2);
//2、包装静态函数
function<void(int, string)>f5 = Test::world;
f5(5, "蓝染");
//3、包装仿函数
Test ta;
function<void(string)>f6 = ta;
f6("浦原喜助");
//4、包装转换为函数指针的对象
Test tb;
function<void(int, string)>f7 = tb;
f7(11, "更木剑八");
//*********************************************************************************************
cout << endl << endl;
//*********************************************************************************************
//可调用函数包装器作为函数参数
A aa(Test::world);
aa.notify(12, "涅茧利");
Test tc;
A bb(tc);
bb.notify(7, "狛村左阵");
return 0;
}
Test 类定义了一个 operator funcptr() 转换函数,它的作用是将 Test 类的对象转换为 funcptr 类型的函数指针(即 void(*)(int, string))。当将 tb 传递给 f7 时,实际上调用了这个转换操作符。
补充:类型转换运算符
operator 目标类型()
{
// 转换逻辑
}
案例
#include <iostream>
using namespace std;
class Box {
public:
Box(double v) : volume(v) {}
// 类型转换运算符:将 Box 对象转换为 double 类型
operator double() const {
return volume;
}
private:
double volume;
};
int main() {
Box b(100.0);
double volume = b; // 隐式调用 operator double()
cout << "Volume: " << volume << endl;
return 0;
}
可调用对象绑定器
可调用对象绑定器:
1、将可调用对象与其参数一起绑定成一个仿函数。
2、将多元(参数个数为n,n>1)可调用对象转换为一元或者(n-1)元可调用对象,即只绑定部分参数。
语法格式
// 绑定非类成员函数/变量
auto f = std::bind(可调用对象地址, 绑定的参数/占位符); //>>>>>>>>>>>>>>>>静态函数可以使用这种方式
// 绑定类成员函/变量
auto f = std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);// >>>>>>>>>>>>>>>>>>>>绑定的是成员第三个参数可以省略
绑定非类成员函数/变量
案例1
#include <iostream>
#include <functional>
using namespace std;
//通过bind得到第二个参数
void callFunc(int x, const function<void(int)>& f)
{
if (x % 2 == 0)
{
f(x);
}
}
void output(int x)
{
cout << x << " ";
}
void output_add(int x)
{
cout << x + 10 << " ";
}
int main(void)
{
// 使用绑定器绑定可调用对象和参数
auto f1 = bind(output, placeholders::_1);// >>>>>> f1类型std::function<void(int)>
for (int i = 0; i < 10; ++i)
{
callFunc(i, f1);
}
cout << endl;
auto f2 = bind(output_add, placeholders::_1);// >>>>>>> f2类型std::function<void(int)>
for (int i = 0; i < 10; ++i)
{
callFunc(i, f2);
}
cout << endl;
return 0;
}
在上面的程序中,使用了std::bind绑定器,在函数外部通过绑定不同的函数,控制了最后执行的结果。std::bind绑定器返回的是一个仿函数类型,得到的返回值可以直接赋值给一个std::function,在使用的时候我们并不需要关心绑定器的返回值类型,使用auto进行自动类型推导就可以了。
placeholders::_1是一个占位符,代表这个位置将在函数调用时被传入的第一个参数所替代。同样还有其他的占位符placeholders::_2、placeholders::_3、placeholders::_4、placeholders::_5等……
案例2
#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);
bind(output, placeholders::_1, placeholders::_2)(10, 20);
bind(output, placeholders::_2, placeholders::_1)(10, 20);
return 0;
}
案例3
#include <iostream>
#include <functional>
using namespace std;
void callFunc(int x, int y, const function<void(int, int)>& f)
{
if (x % 2 == 0)
{
f(x, y);
}
}
void output_add(int x, int y)
{
cout << "x: " << x << ",y: " << y <<
",x+y: " << x + y << endl;
}
int main(void)
{
for (int i = 0; i < 10;