C++中函数表与函数容器

时间:2021-05-07 01:44:29

函数表(function table),是函数映射的表, 最简单的方法是使用”map<>”容器, 映射”std::string”和”function<>”容器;
函数容器的类型是 调用签名(call signature), 如 “std::function

#include<iostream>
#include<map>
#include<string>
#include <functional>
using namespace std;
struct absInt
{
int operator()(int val)const
{
return val < 0 ? -val : val;
}
};
//普通函数
int add(int i, int j) {
return i + j;
}
//lambda表达式,产生一个未命名的函数对象类
auto mod = [](int i, int j) {return i%j; };
//函数对象类,相当于类重载了函数调用运算符,则可以像使用函数一样使用该类的对象
struct divide
{
int operator()(int denominator, int divisor) {
return denominator / divisor;
}
};
int main() {
int i = -42;
absInt absObj;
int ui = absObj(i);//操作符重载,重载函数调用运算符()
cout << ui << endl;
//函数表function table,用于存储指向这些可调用对象的“指针”,当程序要执行某个特定操作时,从表中查找该调用的函数,索引是字符串,值是一个函数指针
map<string, int(*)(int, int)> binops;
binops.insert({ "+",add });//{ "+",add }是一个pair
int rs = binops["+"](10, 5);
cout << rs << endl;
//函数容器function类型,function是一个模板,当创建一个具体的function类型时我们必须提供额外的信息
map<string, function<int(int, int)>> binops2 = {
{"+",add}, //函数指针
{"-",std::minus<int>()}, //标准函数库对象
{"/",divide()}, //用户定义的函数对象
{"*",[](int i,int j) {return i*j; }}, //未命名的lambda表达式
{"%",mod} //命名的lambda表达式
};
std::cout << "10 + 5 = " << binops["+"](10, 5) << std::endl;//调用add(10,5)
std::cout << "10 - 5 = " << binops["-"](10, 5) << std::endl;//使用minus<int>对象的调用运算符
std::cout << "10 / 5 = " << binops["/"](10, 5) << std::endl;//使用divide对象的调用运算符
std::cout << "10 * 5 = " << binops["*"](10, 5) << std::endl;//调用lambda表达式
std::cout << "10 % 5 = " << binops["%"](10, 5) << std::endl;//调用lambda表达式
return 0;
}

例如binops[“+”](10, 5)实际上是使用该指针调用add,并传入10和5。

重载的函数与function

不能直接将重载函数的名字存入function类型的对象中:

    int add(int i, int j) { return i + j; }
Sales_data add(const Sales_data&, const Sales_data&);
map < string, function<int(int, int)> > binops;
binops.insert({"+",add});//哪个add?

解决上面二义性的一个办法是存储函数指针而不是函数的名字:

    int(*fp) (int, int) = add;//指针fp所指向的add是接受两个int的版本
binops.insert({"+",fp});

同样,也可以使用lambda来消除二义性:

    binops.insert({ "+",[](int a,intb) {return add(a,b); } });

lambda内部的函数调用传入了两个int,因此该调用只能匹配接受两个int的add版本,而这也是执行lambda时真正调用的函数。

具体细节可以参考C++ primer 第五版的第14章的内容。