C++可调用对象与函数表
c++的可调用对象 有
- 函数
- 函数指针
- lambda表达式
- bind的对象
- 重载了函数调用运算符的类
如何调用?
函数调用
void afuncToCall()
{
cout << "call me"<<"\n";
}
//1.call function
afuncToCall();
函数指针调用
void func(int i){
cout << "a function called by function pointer i= "<<i<<"\n";
}
//声明一个函数指针
void(*f)(int i);
//对函数指针赋值
f=func;
//调用指针函数
f(5);
或者使用typedef缩写函数指针
//function pointer
typedef void(*AbleCallFuncP)(int i) ;
//2.function pointer
AbleCallFuncP callFuncPointer= func;
callFuncPointer(5);
lambda表达式调用
auto flambda = [](int i){
cout << "lambda i is " << i << "\n";
};
flambda(7);
bind的对象
#include <functional>
void func(int i){
cout << "a function called by bind object i= "<<i<<"\n";
}
auto fbind = bind(func,std::placeholders::_1);
fbind(9);
重载了函数调用运算符的类
struct callableStruct
{
int operator()(int val){
return (val<0)?-val:val;
}
};
// callableStruct callableSut;
int i = callableSut(-2);
函数表
现在,我们拥有了5种函数调用方式,那么,在一个项目里,我们很可能希望使用一个统一的函数表来管理这些函数调用对象,以上面的函数为例,我们其实拥有了5个参数为int类型的调用对象,使用map可以方便地实现函数表;
只是,问题在于,这5种可调用对象的类型是不同的,我们无法将他们使用同一种类型放入map的second字段中,于是万能的C++标准大神们发明了function类模板来解决这个问题。
罗列5种可调对象如下:
//function
void afuncToCall(int i)
{
cout << "call me a plain functon i is "<<i <<"\n";
}
//function pointer
typedef void(*AbleCallFuncP)(int i) ;
//called by function pointer
void func1(int i){
cout << "a function called by function pointer i= "<<i<<"\n";
}
//called by bind
void func2(int i){
cout << "a function called by bind i= "<<i<<"\n";
}
//callable class
struct callableStruct
{
void operator()(int i){
cout << "a function called by callableStruct i= "<<i<<"\n";
}
};
//1.call function
//afuncToCall();
// //2.function pointer
AbleCallFuncP callFuncPointer= func1;
//3.lambda
auto flambda = [](int i){
cout << "lambda i is " << i << "\n";
};
//4 bind
auto fbind = bind(func2,std::placeholders::_1);
//5.operator ()
callableStruct callableSut;
让我们用function统一它们的类型
#include <functional>
#include <map>
#include <string>
// using std::map;
void TestCallableObj()
{
typedef function<void(int)> FuncVI;
typedef map<string,FuncVI> FuncAbleObjMap;
FuncAbleObjMap callableObjMap;
callableObjMap.insert(FuncAbleObjMap::value_type(string("plain function call"),afuncToCall));
callableObjMap.insert(FuncAbleObjMap::value_type(string("function pointer call"),callFuncPointer));
callableObjMap.insert(FuncAbleObjMap::value_type(string("lambda call"),flambda));
callableObjMap.insert(FuncAbleObjMap::value_type(string("bind call"),fbind));
callableObjMap.insert(FuncAbleObjMap::value_type(string("operator() call"),callableStruct()));
callableObjMap["plain function call"](1);
callableObjMap["function pointer call"](2);
callableObjMap["lambda call"](3);
callableObjMap["bind call"](4);
callableObjMap["operator() call"](5);
}
输出结果
call me a plain functon i is 1
a function called by function pointer i= 2
lambda i is 3
a function called by bind i= 4
a function called by callableStruct i= 5
由此可见,通过function模板,我们将类型本不同的5个可调用对象打包成统一的类型,因为它们的返回值和参数类型是完全一样的。通过函数表的使用,我们可以写出封装更好的调用函数。
如果觉得这样的调用太繁琐,可以使用宏来缩写下
比如:
#define CALL1(x) callableObjMap[#x](1);
CALL1(plain function call);
CALL1(bind call);
备注,本文没有涉及到函数成员函数 和静态成员函数的调用,权当归类到函数一类了。但是其调用细节和函数还是有差异的。