C++函数包装器
文章目录
为什么需要函数包装器
函数包装器
bind调整可调用类型的参数
为什么需要函数包装器
function函数包装器也叫适配器,在C++中其本质是一个类模板。
由于C++的历史遗留问题,导致如果想实现一个函数功能,可以采用函数名、函数指针、仿函数、有名称的lambda表达式,所有这些都是可调用的类型。
它们存在很多问题:
函数指针类型太复杂,不方便使用和理解
仿函数类型是一个类名,没有指定调用参数和返回值,得去看operator()的实现才能看出来。
lambda表达式在语法层,看不到类型,只能在底层看到其类型,基本都是lambda_uuid。
比如ret=func(x)这个函数调用,func有可能是上面的任意一种。
类型如此丰富,可能导致模板的效率极低。
#include<iostream>
using namespace std;
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;
cout << useF([](double d)->double {return d / 4; }, 11.11) << endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
编译器会根据传入的F类型不同,实例化出三种不同的函数,所以静态变量count就会有三种不同的地址。
很显然这并不很合适,因为不管是函数名、函数指针、仿函数还是lambda表达式,它们都是一个“函数”,所以如果它们能够统一类型,这样模板就会实例化出一份对象,从而提高效率。
函数包装器
包装器可以很好地解决这个问题,它统一可调用对象类型,并且指定了参数和返回值类型。
function函数包装器的写法为:
function<函数返回值类型(函数参数类型)>包装器名称=要包装的函数。
1
其在头文件<functional>中
#include<iostream>
#include<functional>
using namespace std;
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;
}
};
class Func
{
public:
static double f1(double i)
{
return i / 4;
}
double f2(double i)
{
return i / 5;
}
};
int main()
{
function<double(double)>func1 = f;
function<double(double)>func2 = Functor();
function<double(double)>func3 = [](double d)->double {return d / 4; };
function<double(double)>func4 = Func::f1;
//非静态成员函数要传this指针,因此参数要加上Func,且要取地址
function<double(Func,double)>func5 = &Func::f2;
//调用包装器包装的函数
cout << func1(11.11) << endl;
cout << func2(11.11) << endl;
cout << func3(11.11) << endl;
cout << func4(11.11) << endl;
//传入非静态成员函数时,要额外传入一个对象
cout << func5(Func(),11.11) << endl;
//func1到func5都会被当做一种类型
cout << useF(func1, 11.11) << endl;
cout << useF(func2, 11.11) << endl;
cout << useF(func3, 11.11) << endl;
cout << useF(func4, 11.11) << endl;
//cout << useF(func5, 11.11) << endl;
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
bind调整可调用类型的参数
可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原来对象的参数列表。它可以用来绑定一个类对象,这样调用绑定的成员函数时就不需要传入一个类对象了。
#include<iostream>
#include<functional>
using namespace std;
int Plus(int a, int b)
{
return a + b;
}
class Sub
{
public:
int sub(int a, int b)
{
return a - b;
}
};
int main()
{
function<int(int,int)>f1=bind(Plus, placeholders::_1, placeholders::_2);
cout << f1(1, 2) << endl;//3
//把plus绑定成一个值+10,相当于只传一个参数,另一个参数固定为10
function<int(int)>f2 = bind(Plus, 10, placeholders::_1);
cout << f2(4) << endl;//14
//绑定很好地解决了调用成员函数必须要先出入一个对象的问题,它直接绑定了一个对象
function<int(int, int)>f3 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);
cout<<f3(1, 2) << endl;//-1
//控制传入参数的顺序,将 placeholders::_1和 placeholders::_2交换顺序
//这样传入的第一个参数就会作为sub(int a,int b)中的b,第二个参数作为a
//这主要是因为_2是和b绑定的,_1和a绑定,先传入的参数是_2,再传入_1
function<int(int, int)>f4 = bind(&Sub::sub, Sub(), placeholders::_2, placeholders::_1);
cout << f4(1, 2) << endl;//1
return 0;
}
————————————————
版权声明:本文为CSDN博主「今天也要写bug、」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_52670477/article/details/122863545
https://blog.csdn.net/qq_52670477/article/details/122863545
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」