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);

备注,本文没有涉及到函数成员函数 和静态成员函数的调用,权当归类到函数一类了。但是其调用细节和函数还是有差异的。

posted @ 2018-12-04 21:46  Lckfa  阅读(940)  评论(0编辑  收藏  举报