# 函数容器 ​ 以`vector`容器为例,制作一个储存函数的容器: > 由于VC++编译器对typeid().name()的支持比较人性化,本文选用VC++2017为编译器。 ## 普通函数容器 ​ 普通函数,即:非类成员函数。 ### 函数的类型 ​ 实现先看看函数的类型: ```c++ void f(){} cout << typeid(f).name() << endl << typeid(void()).name() << endl << typeid(int()).name() << endl << typeid(int(int)).name() << endl; ``` 输出结果如下: ```c++ void __cdecl(void) void __cdecl(void) int __cdecl(void) int __cdecl(int) ``` #### 性质 ```c++ #include std::is_move_assignable::value; // void(void)是否可移动、可转让?----否 ``` ### 函数指针类型: ```c++ void f(){} cout << typeid(&f).name()<< endl; ``` 输出结果如下: ```c++ void (__cdecl*)(void) ``` #### 性质 ```c++ #include std::is_move_assignable::value; // void(void)是否可移动、可转让?----是 ``` ### 函数类型容器 ​ 首先尝试声明函数类型容器: ```c++ vectorlst_fic; lst_fic.push_back(f); ``` ​ 编写过程无误,但是VC++和GCC8下编译失败。 GCC8提示如下: > required from 'class std::allocator' 很明显,要求提供void()类型的分配器,但是标准库中并未提供。说明无法声明函数类型容器。 ### 函数类型数组 ```c++ decltype(int()) arr_fic[5]; // 这个是int数组,而不是int(void) decltype(f) arr_fic[5]; ``` ​ 在编译第二条语句时报错: > “arr_fic”数组元素类型不能是函数或抽象类类型 ### 函数指针类型数组 ````c++ void f() { cout << "f()" << endl; } void f1() {} using type_f=void (*)(); // 本来想用typename 但是发现没什么用 type_f p_f_array[2]{// 此处可写作:decltype(f) p_f_array[2]; f, f1// 该容器只能容纳void(void)类型 }; p_f_array[0](); cout << typeid(p_f_array).name() << endl << typeid(p_f_array[0]).name(); ```` 输出结果如下: ```c++ f() void (__cdecl*[2])(void) void (__cdecl*)(void) ``` ### 函数指针容器 ```c++ vector vec_fic{ f, f1 }; vec_fic.at(0)(); cout << typeid(vec_fic).name() << endl << typeid(vec_fic[0]).name() << endl; ``` 结果如下: ```c++ f() class std::vector > void (__cdecl*)(void) ``` ## 类函数容器 ​ 类成员函数的行为与普通函数的行为不同,由于非静态成员函数的调用必须要先声明对象。`class::f`被认为是调用类成员函数,导致必须先声明一个对象。获取类成员函数地址的方式是进行取地址:`&class::f`。 以此类为例: ```c++ class A{ public: void f(){ cout<<"f()"< vec_mbr{ &A::f, &A::f1 }; A a; (a.*vec_mbr[0])(); cout << typeid(vec_mbr).name() << endl << typeid(vec_mbr[0]).name(); ``` 输出结果如下: ```c++ f() class std::vector > void (__cdecl A::*)(void) __ptr64 ``` ## 总结 ​ 虽然函数名就代表了函数地址,但是函数名的类型和函数指针的类型不同。而且由于函数的大小不固定,因此无法创建函数数组,但是函数指针的大小是固定的,因此可以创建函数指针的数组和容器。 ## decltype()与typeid的不一致 typeid将int()识别为int \-\-cdecl(void) 而decltype识别为int ```c++ decltype(f) a; p_f_array[0](); cout << typeid(f2).name() << endl << typeid(a).name(); // a(); 该行无法link出错 ``` 。