引入
- 在介绍function之前,先介绍下面的知识:
- 有时,不同类型的对象可能共享同一种调用形式。例如下面的三种类型,都共享同一种调用形式:int(int,int);
int add(int i, int j) { return i + j; }
auto mod = [](int i, int j) {return i * j; };
struct divide
{
int operator()(int denominator,int divisor)
{
return denominator / divisor;
}
};
- 为了使用这些可调用对象,我们可以定义一个函数表用于存储指向这些可调用对象的“指针”。我们可以通过map来实现:
- 参数1用一个string来表示这个对象可以用来干嘛
- 参数2为函数指针
map<string, int(*)(int,int)> binops;
binops.insert({ "+",add });//正确
binops.insert({ "%",mod });//错误
- 然后第二个是错误,因为lambda是个表达式,每个lambda都有自己的类类型,该类型与存储在binops中的值的类型不匹配
一、function模板简介
- 我们可以用function的标准库类型解决上述问题
- 新版本标准库中的function类与旧版本中的unary_function和binary_function没有关联,后两个类已经被更通用的bind函数替代了
二、使用
- 当使用该模板时,必须提供额外的信息来表示能够表示的对象的调用形式
演示案例
- function模板接受两个int、返回一个int的可调用对象
function<int(int, int)> f1 = add; function<int(int, int)> f2 = divide(); function<int(int, int)> f3 = [](int i, int j) {return i*j; }; cout << f1(4,2)<< endl; //6 cout << f2(4, 2) << endl;//2 cout << f3(4, 2) << endl;//8
重新定义map
- 我们通过使用function模板重新定义上面的map
map<string, function<int(int, int)>> binops; binops = { {"+",add}, {"-",std::minus<int>()}, {"/",divide()}, {"*",[](int i,int j) {return i*j; }}, {"%",mod} }; binops["+"](10, 5); //调用add(10,5); binops["-"](10, 5); //使用minus<int>对象的调用运算符 binops["/"](10, 5); //使用divide对象的调用运算符 binops["*"](10, 5); //调用lambda函数对象 binops["%"](10, 5); //调用lambda函数对象
三、重载的函数与function模板的关系
- 规则:不能直接将重载函数的名字存入到function类型的对象中,会产生二义性
- 解决方法:在模板中存储函数指针而非函数的名字
错误演示以及正确案例
- 错误案例
int add(int i, int j); long add(long i, long j); map<string, function<int(int, int)>> binops; binops.insert({ "+",add });//错误,产生二义性
- 正确方法
int add(int i, int j); long add(long i, long j); int(*fp)(int, int) = add; //函数指针 map<string, function<int(int, int)>> binops; binops.insert({ "+",fp });//正确
- 同样,我们也能使用lambda来消除二义性。lambda内部的函数传入了两个int,因此该调用只能匹配接受两个int的add函数版本,而这也正是执行lambda时真正调用的函数
int add(int i, int j); long add(long i, long j); map<string, function<int(int, int)>> binops; binops.insert({ "+",[](int a,int b) {return add(a,b); } })