需求:对于多个可调用对象共享同一种调用形式的情况,有时我们会希望把它们看成具有相同的类型。例如,
// 普通函数
int add(int i, int j) {
return i+j;
}
// lambda表达式
auto mod = [] (int i, int j) {
return i%j;
}
// 函数对象类
struct divide {
int operator()(int i, int j) {
return i/j;
}
};
尽管它们的类型各不相同,但却共享同一种调用形式:int(int, int)
.
问题:正因为它们类型不相同,所以以下操作不合法!
map<string, int(*)(int,int)> binops;
binops.insert({"+", add}); // ok
binops.insert({"%", mod}); // 错误:mod不是一个函数指针
解决办法:使用 function 模板
-
function类型定义在 <functional> 头文件中。
-
常用操作如下
函数声明 解释 function<T> f f 是一个用来存储可调用对象的空function。
这些可调用对象的调用形式应与函数类型 T 相同,即 T 是 returnType(params_types)function<T> f(nullptr) 显式构造一个空的 function function<T> f(obj) 在 f 中存储可调用对象 obj 的副本 f 将 f 作为判断条件,当 f 含有一个可调用对象时为真 f(args) 调用f中的对象,参数为args
function类型可以将具有相同调用形式而却具有不同类型的可调用对象统一起来,使用以下方法可以解决上述问题:
map<string, function<int(int,int)>> binops = {
{"+", add},
{"%", mod},
{"/", divide()}
}; // 完全ojbk
binops["+"](10, 5); // add(10, 5)
重载函数与function
我们不能(直接)将重载函数的名字存入 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; // 接受两个 int 类型参数的那个版本的 add
binops.insert({"+", fp}); // ok