文章目录

  • 可调用对象和调用形式
  • 函数表的例子
  • 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});//错误

两种解决方法:

  1. 使用函数指针,明确指向某一个函数
  2. 使用lamda,调用特定版本的函数
binops.insert({"+",[](int i,int j){return add(i,j);}});