C++语言中有几种可调用的对象:函数、函数指针、lambda表达式、bind创建的对象、以及重载了函数调用运算符的类。
可调用的对象也有类型,例如,每个lambda有它自己唯一的(未命名)类类型,函数及函数指针的类型由其返回值类型和实参类型决定。
不同类型可能具有相同的调用形式
//普通函数
int add(int i, int j) { return i + j; }
//lambda,其产生一个未命名的函数对象类
auto mod = [](int i, int j) { return i % j; };
//函数对象类
class divide {
int operator() (int denominator, int divisor)
{
return denominator / divisor;
}
}
上面这些可调用对象分别对其参数执行了不同的算术运算,尽管它们的类型各不相同,但是共享同一种调用形式:int (int , int)
可以通过定义一个函数表来存储指向这些可调用对象的”指针“。当程序需要某执行某个特定的操作时,从表中查找该调用的函数。在C++中,函数表可以通过map来实现
标准库function类型
function定义在functional头文件中,下表列出了function定义的操作:
function是一个模板,当创建一个具体的function类型时,必须提供额外的信息,例如function
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;
cout<<f2(4, 2)<<endl;
cout<<f3(4,2)<<endl;
使用function类型重新定义map:
map<string, function<int(int, int)>> binops;
可以把所有可调用对象,包括函数指针,lambda或者函数对象在内,都添加到这个map中:
map<string, function<int(int, int)>> binops = {
{"+", add},
{"-", std::minus<int>()}, {"/",divide()},
{"*", [](int i, int j) { return i*j; }},
{"%", mod}
};
则调用形式为:
binops["+"](10,5);
binops["-"](10,5);
binops["/"](10,5);
binops["*"](10,5);
重载的函数与function:
不能直接将重载函数的名字存入function类型的对象中
int add(int i, int j) { return i+j; }
Sales_data add(const Sales_data&, const Sales_data&);
map<string, fucntion<int(int, int)>> binops;
binops.insert({"+", add}); //错误,哪个?
解决上述二义性问题的一条途径是存储函数指针而非函数的名字:
int (*fp)(int, int) = add; //指针所指的add是接受两个int的版本
binops.insert({"+", fp}); //正确:fp指向一个正确的add版本
同样可以使用lambda来消除二义性:
//正确:使用lambda来指定我们希望使用的add版本
binops.insert({"+", [](int a, int b){ return add(a,b)}});
lambda内部使用的函数调用传入了两个int,因此该调用只能匹配接受两个int的add版本。