文章目录
- 可调用对象和调用形式
- 函数表的例子
- function救场
- 重载函数二义性问题
可调用对象和调用形式
C++中有几种可调用对象:
1.函数
2.函数指针
3.重载了调用运算符的类
4.lambda表达式
5.bind创建的对象
可调用对象有不同的类型,每个lambda有唯一的类类型,函数和函数指针的类型由参数和返回值决定。
不同类型的可调用对象可能有相同的调用形式,调用形式表明了调用返回的类型和传递给调用的实参类型,一种调用形式对应一个函数类型。如:
int(int,int)
是一个函数类型,它接受两个int,返回一个int
函数表的例子
考虑不同类型的可调用对象:
int add(int i,int j){return i+j};//函数类型
auto mod=[](int i,int j){return i%j};//lambda对应一个未命名的函数对象类
struct divide{//函数对象类
int operator()(int i,int j){
return i/j;
}
}
以上三个可调用对象具有不同的类型,但是有相同的调用形式。
假设我们希望将上述函数对象做成一个函数表来进行调用,声明map:
map<string,int(*)(int,int)> binops;
添加add到map中
binops.insert({"+".add});//正确
但是我们不能将mod和divide加入map中,原因是mod和divide是类类型,而不是一个函数指针,与binops中的值类型不匹配
function救场
使用function标准库类型可以解决以上问题。function是一个模板,创建一个具体的类类型时我们需要提供额外的信息:调用形式。如:
function<int(int,int)>
这里声明了一个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};
重新声明map,我们就能把所有具有该调用形式的可调用对象添加到map中
binops.insert({"%",f2});
binops.insert({"/",f3});
//调用
binops["/"](10,5)//使用对象的调用运算符 =2
binops["%"](10,5)//调用lambda函数对象 =0
重载函数二义性问题
重载函数由于函数名相同,插入map时,会产生二义性问题:
int add(int i,int j);
float add(float i,float j);
binops.insert({"+",add});//错误
两种解决方法:
- 使用函数指针,明确指向某一个函数
- 使用lamda,调用特定版本的函数
binops.insert({"+",[](int i,int j){return add(i,j);}});