目录
- function
- bind
function
目前,我们的知识深度已知的可调用对象类型有:
- 函数指针
- 仿函数 / 函数对象
- lambda表达式
现在我们有一个函数模板
template<class F, class T> T useF(F f, T x) { static int count = 0; cout << "count:" << &count << endl; return f(x); }
对于函数模板,编译器会根据实参,按照模板定义出一份特定的函数。
函数内部的静态成员变量是属于函数的,无论调用多少次该函数,都只会定义出一个。
记住上面这两个知识点,现在增加一个函数和仿函数,用来测试useF
函数模板
int Sub(int num) { return (num - 2); } struct Func { int operator()(int num) { return (num - 3); } }; int main() { // 函数名 cout << useF(Sub, 4) << endl; // 函数对象 cout << useF(Func(), 4) << endl; // lambda表达式 cout << useF([](int d)->int{ return (d - 4); }, 11.11) << endl; return 0; }
解释运行结果:我们在函数模板内部实现打印静态成员变量,发现三次打印的cout地址不一样。然而静态成员变量是属于函数的,一个函数的静态成员变量无论调用多少次都只有一份。这说明是三个不同的函数调用。
以lambda表达式为例,一个lambda表达式语句就生成一个自定义类型(仿函数),那么多次调用会根据模板产生非常多的函数。
int main() { // 函数名 cout << useF(Sub, 4) << endl; // 函数对象 cout << useF(Func(), 4) << endl; // lamber表达式 cout << useF([](int d)->int{ return (d - 4); }, 11.11) << endl; cout << useF([](int d)->int { return (d - 4); }, 11.11) << endl; return 0; }
其他可调用对象的类型也是很多的,许多的函数指针,许多的仿函数类,许多的lambda表达式……。类型太丰富了!对于一个模板而言,类型不同,就会对应定义出一份。模板的效率也降低了太多。
C++11提供了包装器,包装器可以将可调用对象统一包装成一个类型。function就是一个包装器,也可称为适配器
function
#include <functional> template <class Ret, class... Args> class function<Ret(Args...)>;
Ret(Args…):第一个模板参数类型(参数包)
测试:
template<class F, class T> T useF(F f, T x) { static int count = 0; //cout << "count:" << ++count << endl; cout << "count:" << &count << endl; return f(x); } int main() { function<int(int)> f1 = [](int d)->int { return (d - 4); }; function<int(int)> f2 = [](int d)->int { return (d - 4); }; function<int(int)> f3 = [](int d)->int { return (d - 4); }; // lamber表达式 cout << useF(f1, 5) << endl; cout << useF(f2, 5) << endl; cout << useF(f3, 5) << endl; return 0; }
上面调用的都是同一个函数。
一个lambda表达式语句会生成一个类,上面有三个lambda表达式语句,生成三个类。使用function包装器将这些可调用对象包装成了一个类型,模板也就只需要定义出一份特定的,极大地提升了模板的效率。
【普通函数指针】
包装用法:function<Ret(Args...)> 对象名 = 函数指针
//例如 int Sub(int x, int y) { return x - y; } int main(void) { //包装函数指针 function<int(int, int)> f1 = Sub; cout << f1(12, 8) << endl; return 0; }
【仿函数】
包装用法:function<Ret(Args……) 对象名 = 仿函数类()
class Sub { public: int operator()(int x, int y) { return (x - y); } }; int main(void) { function<int(int, int)> f2 = Sub(); return 0; }
【静态类成员函数指针】
包装方法:function<Ret(Args……) 对象名 = &类域::函数指针
& 可以不加,不影响结果,但是加上要更优一些。
class Sub { public: static int SubStatic(int x, int y) { return (x - y); } }; int main(void) { function<int(int, int)> f2 = &Sub::SubStatic; cout << f2(10, 3) << endl; function<int(int, int)> f3 = Sub::SubStatic; cout << f2(10, 3) << endl; return 0; }
【非静态类成员函数指针】
包装方法:function<Ret(类域名, Args……) 对象名 = &类域::函数指针
class Sub { public: int SubMember(int x, int y) { return (x - y); } }; int main(void) { function<int(Sub, int, int)> f4 = Sub::SubMember; cout << f4(Sub(), 3, 1) << endl; return 0; }
非静态类成员函数指针包装后,使用包装后的对象进行调用,第一个参数,必须是类名。
【lambda表达式】
包装方法:function<Ret(Args……) 对象名 = lambda表达式
int main(void) { function<double(double, double)> f5 = [](double x, double y)mutable->double {return x - y; }; cout << f5(2.23, 1.11) << endl; return 0; }
bind
bind也是一个包装器。
作用一:调整参数的顺序
普通函数指针的包装方法:function<Ret(Args...)> 对象名 = bind(函数指针,newArgs……)
int Sub(int x, int y) { return x - y; } int main(void) { //function、bind包装函数指针 function<int(int, int)> f1 = Sub; //将第一个参数和第二个参数交换 function<int(int, int)> f2 = bind(Sub, placeholders::_2, placeholders::_1); cout << f1(12, 8) << endl; cout << f2(12, 8) << endl; return 0; }
placeholders::_n,表示当前function类中参数包的第n个参数。
希望怎么调整参数的顺序,就在调用bind函数时,传递什么样的参数顺序。bind函数传参时,使用placeholders::_n。
作用二、指定某个参数的值
#include <iostream> #include <functional> using namespace std; int Sub(int x, int y) { return x - y; } int main(void) { //function、bind包装函数指针 function<int(int, int)> f2 = bind(Sub, 10, placeholders::_2); cout << f2(12, 8) << endl; return 0; }
使用function和bind包装过后,并且指定了某个参数的值。function实例化的时候可以省略掉指定了值的参数的参数类型。省略掉后要注意维护bind函数内的参数包。
int Sub(int x, int y) { return x - y; } int main(void) { //function、bind包装函数指针 function<int(int)> f2 = bind(Sub, 10, placeholders::_1); cout << f2(8) << endl; return 0; }
可得出结论,bind的间接作用:调整参数的个数。
到此这篇关于C++11新增的包装器详解的文章就介绍到这了,更多相关C++包装器内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!