C++ 新特性学习(四) — Bind和Function
绑定函数是我认为C++新标准里第二有用的库了 绑定库的使用环境是:
GCC-C++ 4.3 及以上
Visual Studio 2008 SP1 及以上
BOOST 1.25及以上(其中function是1.16及以上)
先来看一段代码
木有错,这是C++,并且很方便地实现了委托 这就是传说中的绑定库和增强型的函数对象 接下来一个一个来
Bind
可用于绑定函数、成员函数、函数对象、成员变量 这是老标准中std::bind1st和std::bind2nd的增强版,这两个函数只能且必须绑定一个带有两个参数的,并且只能且必须传入一个自定义参数。但是bind函数支持最多10个自定义参数。
在这里,std::bind函数返回绑定对象,后面跟的(x)表示传参x并执行。 std::placeholders::_1是占位符,表示调用时的第一个参数,这段代码里表示x 如果代码是std::bind(f, std::placeholders::_2, std::placeholders::_1)(x, y) 则表示执行 f(y, x) 另外,在调用前传入的函数参数会被复制并保存在std::bind返回的对象里,比如之前的std::bind(f, 5, std::placeholders::_1)中的5就被存储在了返回的对象里。所以为了性能上考虑,建议传入的类型为引用或指针,避免结构复制
另外,除了普通函数外,std::bind也支持成员函数,但是和普通函数不同,成员函数绑定的第二个参数必须是函数实例。如
由于第二个参数的函数实例的保存方式与参数一致,所以也建议传入类引用或类指针,或者智能指针。 另外,std::bind还可以用于绑定成员变量,和函数结构,绑定函数变量的方法类似成员函数,绑定函数结构的方法类似普通函数 再来一个std::bind稍微复杂一点的应用的例子,和算法库配合使用
最后是bind函数的总结:
函数使用形式:
bind(f [,t][,…]) // 自动推断
bind<返回值类型>(f [,t][,…]) // 非自动推断
bind<返回值类型, 函数类型, 绑定器传入参数类型>(f ,[…]) // 非自动推断
bind<返回值类型, 函数参数类型, 绑定器传入参数类型>(f [,…]) // 非自动推断
bind<返回值类型, 类, 绑定器传入参数类型(即对应的类实例)>(T::*f ,t [,…]) // 非自动推断
bind<返回值类型, 类, 函数参数类型, 绑定器传入参数类型(即对应的类实例+函数传入的参数), >(T::*f ,t [,…]) // 非自动推断
绑定组合
需要注意的问题:
绑定参数数量不匹配将会在绑定时编译错误(特别注意的是绑定类成员时遗漏类实例)
绑定参数类型不匹配将会在调用时编译错误
占位符不匹配将会在调用时编译错误
绑定对象必须是函数或成员函数指针
绑定对象默认为c++函数且不支持变长参数函数,如printf,某些编译器上extern “C”的函数(如: std::strcmp)也不支持(经过检测,G++和VC++都没问题)
支持”stdcall”, “cdecl”, “__fastcall” 和 “pascal” 前缀,但是绑定这些函数时要注意加一些定义(boost库是这样,tr1不知道)
对于函数重载的绑定,由于绑定时不能自动确定是哪一个函数,所以会绑定失败,可以使用类型转换或使用局部变量指定这些函数(VC++支持对重载函数的函数类型推断)
由于std::bind的函数参数类型推断和传入参数类型推断是分开的,所以如果函数的参数是引用类型,绑定参数的时候一定要用std::ref(详见 https://www.owent.net/2012/558.html ),否则会复制临时对象传入的,而不是传入引用类型。如:
bind函数的返回结果不包含STL中一元或二元函数的概念,因为其缺少result_type 和 argument_type 或 first_argument_type 和 second_argument_type的定义(经检测VC++和G++的bind返回结果包含result_type定义)(转换成std::function后如果是一元或二元函数则支持以上定义)
标准要求至少有10个占位符,而G++支持30个占位符
Function
这东西是针对函数对象的多态包装器(又称多态函数对象包装器),函数对象又称仿函数。 std::function的作用就在于把函数或函数对象转换成function对象,并用于保存和后期调用。 其中和std::bind的配合使用的例子上面已经有了,就不重复。 std::function同样支持函数、成员函数、函数变量和函数结构。 std::function和std::bind配合使用时是把std::bind返回的结果作为函数对象使用的。
函数对象的例程:
但是成员变量和成员函数稍有不同,在申明时函数第一个类型必须是类的类型(或指针),传入参数是也同样。如:
继续总结吧:
使用形式
std::function<函数申明>,如:std::function fn;
std::function和函数指针的优劣
std::function 允许任意可转换的函数
std::function 可以和其他参数或函数绑定对象库配合使用
当空函数结构调用的时候 std::function 的行为可以预见, 类型安全
函数指针更小
函数指针更快(std::function 在析构时可能会释放函数对象)
函数指针对C语言库的向后兼容性更好
函数指针的错误信息更容易理解
性能
对象大小: 包含两个函数指针的大小
复制性能: 取决于所关联的函数或函数对象,建议采用函数或函数对象的引用传给std::function来提高复制性能
执行性能: 对一个正常的内联编译器而言,将会通过函数指针执行函数调用。如果关联到函数对象,析构时会进释放该对象
Last updated