C++ bind函数
std::bind
简单调用(1)template /* 未指定 */ bind (Fn&& fn, Args&&... args);跟上返回值(2)template /* 未指定 */ bind (Fn&& fn, Args&&... args);
绑定(Bind)函数与参数的作用,
返回一个基于fn的函数对象,但是已经提前绑定了调用需要的参数。
调用这个函数对象相当于调用用绑定的参数调用fn。
下面给你一个使用例子吧:
// bind 用例#include #include // 自定义的一个函数double my_divide (double x, double y) {return x/y;}// 自定义的一个结构体struct MyPair { double a,b; double multiply() {return a*b;}};int main () { // 这个using是为了使用 _1, _2, _3,... using namespace std::placeholders; // 捆绑函数: auto fn_five = std::bind (my_divide,10,2); // 返回 10/2 std::cout (my_divide,_1,_2); // 返回 int(x/y) std::cout << fn_rounding(10,3) << '
'; // 输出 3 MyPair ten_two {10,2}; // 捆绑成员函数: auto bound_member_fn = std::bind (&MyPair::multiply,_1); // 返回 x.multiply() std::cout << bound_member_fn(ten_two) << '
'; // 输出 20 auto bound_member_data = std::bind (&MyPair::a,ten_two); // 返回 ten_two.a std::cout << bound_member_data() << '
'; // 输出 10 return 0;}运行结果:
550.232010
bind是一组用于函数绑定的模板。在对某个函数进行绑定时,可以指定部分参数或全部参数,也可以不指定任何参数,还可以调整各个参数间的顺序。对于未指
定的参数,可以使用占位符_1、_2、_3来表示。-1表示绑定后的函数的第1个参数,_2表示绑定后的函数的第2个参数,其他依次类推。
bind可以绑定到普通函数、函数对象、类的成员函数和类的成员变量。先介绍最简单的这种试试理解。
普通函数
1 void nine_arguments(int i1,int i2,int i3,int i4,int i5,int i6,int i7,int i8,int i9);
int i1=1, i2=2, i3=3, i4=4, i5=5, i6=6, i7=7, i8=8, i9=9;
2bind(nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7 (i1,i2,i3,i4,i5,i6,i7,i8,i9);
3bind(nine_arguments,i9,i2,i1,i6,i3,i8,_1,_2,_1) (i8,i9);
4bind(nine_arguments, i9,i2,i1,i6,i3,i8,i4,i5,i7) ();
上述5个例子中:
1是普通函数形势
2是指,对1这个函数,我们更换其中参数的顺序,你看nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7,后面跟的第一个指定的占位符是9,所以意思是,对后面括号里的第一个参数i1,把他的值赋给原函数
void nine_arguments(int i1,int i2,int i3,int i4,int i5,int i6,int i7,int i8,int i9)
里的第9个参数,后面的依次对应。最终等价于调用函数nine_arguments(i3,i2,i5,i7,i8,i4,i9,i6,i1)
理解2的基础上,3等价于nine_arguments(i3,i2,i5,i7,i8,i4,i8,i9,i8)
应该是这样。。
bind可以绑定到普通函数、函数对象、类的成员函数和类的成员变量。下面分别进行介绍。
1、普通函数
1 void nine_arguments(int i1,int i2,int i3,int i4,int i5,int i6,int i7,int i8,int i9);
2 int i1=1, i2=2, i3=3, i4=4, i5=5, i6=6, i7=7, i8=8, i9=9;
3 bind(nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7(i1,i2,i3,i4,i5,i6,i7,i8,i9);
4 bind(nine_arguments,i9,i2,i1,i6,i3,i8,_1,_2,_1)(i8,i9);
5 bind(nine_arguments, i9,i2,i1,i6,i3,i8,i4,i5,i7)();
2、函数对象
1 class CStudent
2 {
3 public:
4 void operator() (string strName, int nAge)
5 {
6 cout << strName << " : " << nAge << endl;
7 }
8 };
9 bind(CStudent(), "Mike", _1)(12);
3、类的成员函数
1 struct TAdd
2 {
3 int Add(int x,int y)
4 {
5 return x+y;
6 }
7 };
8 TAdd tAdd;
9 TAdd *p = new TAdd();
10 shared_ptr<TAdd> *q(p);
11 bind(TAdd::Add, tAdd, 2, 3)();
12 bind(TAdd::Add, p, 2, 3)();
13 bind(TAdd::Add, q, 2, 3)();
4、类的成员变量
1 void Output(const string &name)
2 {
3 cout << name << endl;
4 }
5
6 map<int, string> map1;
7 for_each(map1.begin(), map1.end(), bind(Output, bind(map<int,
8 string>::value_type::second, _1)));
bind还可以进行嵌套绑定。假设有一个CPerson类,该类有一个获取年龄的接口int GetAge(),现在有一个CPerson对象的vector,需要对其进行排序,则可以如下使用bind:
1 vector<CPerson> vctPerson;
2 sort(vctPerson.begin(), vctPerson.end(), bind(less<int>(),
3 bind(CPerson::GetAge, _1), bind(CPerson::GetAge, _2)));
假设有一个整数的vector, 现在想要获取其中大于20但小于30的整数的个数,则有:
1 count_if(vctNum.begin(), vctNum.end, bind(logic_and<bool>(),
2 bind(greater<int>(), _1, 20), bind(less<int>(), _1, 30)));
在使用bind时,还有一些需要特别注意的地方,下面逐一进行介绍。
1、对于指定了值的参数,bind返回的函数对象会保存这些值,并且缺省是以传值方式保存的。考虑下面的代码:
1 void inc(int &a) { a++; }
2 int n = 0;
3 bind(inc, n)();
调用bind返回的函数对象后,n仍然等于0。这是由于bind时,传入的是n的拷贝。如果需要传入n的引用,则可以使用ref或cref函数,比如:
1 bind(inc, ref(n))(); // n现在等于1了
2、bind的第一个参数是一个函数对象,不能用占位符来代替。考虑下面的代码:
1 typedef function<void (int)> Func;
2 vector<Func> vctFunc;
3 for_each(vctFunc.begin(), vctFunc.end(), bind(_1, 5)); // 编译出错
此时,可以借助apply模板。apply模板的第一个参数是传入的函数对象,后面可以有若干个参数,表示函数对象的参数。比如:
1 apply<void> a; // void是函数对象的返回值类型
2 a(f); // 相当于调用f()
3 a(f, x); // 相当于调用f(x)
4 a(f, x, y); // 相当于调用f(x, y)
使用apply后,我们可以将vctFunc中的元素当作占位符传递过来。参考代码如下:
1 for_each(vctFunc.begin(), vctFunc.end(), bind(apply<void>(), _1, 5));
-- 本文来源于创世软件团队博客, 原文地址: http://www.cnblogs.com/hujian/archive/2012/12/08/2809298.html
placeholders是std命名空间的子命名空间。
绑定函数bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this值。不同于call和apply只是单纯地设置this的值后传参,它还会将所有传入bind()方法中的实参(第一个参数之后的参数)与this一起绑定。
关于这个特性看《JS权威指南》原文的例子:
var sum = function(x,y) { return x + y }; var succ = sum.bind(null, 1); //让this指向null,其后的实参也会作为实参传入被绑定的函数sum succ(2); // => 3: 可以看到1绑定到了sum函数中的x
其次, bind()方法所返回的函数的length(形参数量)等于原函数的形参数量减去传入bind()方法中的实参数量(第一个参数以后的所有参数),因为传入bind中的实参都会绑定到原函数的形参,举个例子:
function func(a,b,c,d){...} //func的length为4 var after = func.bind(null,1,2); //这里输入了两个实参(1,2)绑定到了func函数的a,b console.log(after.length); //after的length为2
第三,当bind()所返回的函数用作构造函数的时候, 传入bind()的this将被忽略,实参会全部传入原函数,这样说很抽象,举个例子:
function original(x){ this.a = 1; this.b = function(){return this.a + x} } var obj={ a = 10 } var newObj = new(original.bind(obj, 2)); //传入了一个实参2 console.log(newObj.a); //输出1, 说明返回的函数用作构造函数时obj(this的值)被忽略了 console.log(newObj.b()); //输出3 ,说明传入的实参2传入了原函数original
以上就是ES5中bind方法的特性, 这种技术也被称为函数柯里化。这种技术将多个参数的函数变成只带一个参数的函数。bind方法就是该技术在js中的实践。
C++ bind函数
1 void inc(int &a) { a++; } 2 int n = 0;3 bind(inc, n)();调用bind返回的函数对象后,n仍然等于0。这是由于bind时,传入的是n的拷贝。如果需要传入n的引用,则可以使用ref或cref函数,比如:1 bind(inc, ref(n))(); \/\/ n现在等于1了 2、bind的第一个参数是一个函数对...
C++11中的std::function和std::bind
std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数更加的灵活和便利。三、std::bind 可将std::bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。 std::bind...
VS2013,C++ bind报错,求高人指点!
bind(check_size, "what", _2);这句的意思是将string类型的“what”作为绑定后的check_size()函数的第二个参数,而你的原函数的第二个参数是 vector<int>类型,所以报错。
关于vc++里面htonl()函数的使用疑惑
其中0x0012ff40、0x0012ff41、0x0012ff42、0x0012ff43这四个单元的值依次为:00、40、32、14,即把原数0x403214的高位部分存放在低位地址中,低位部分存放在高位地址中。由此可见,如果一个数以小尾顺序存储,经htonl函数调用后这个数的高地位字节会完全颠倒过来成为一个新的数。这个新的数在机器内部...
C++已经有了引用操作符&为什么C++11还要引入std:ref
首先,&是类型说明符,而std::ref是一个函数,返回std::reference_wrapper(类似于指针)。为什么需要std::ref?(std::cref类似)主要是考虑到c++11中的函数式编程,例如:std::bind。示例:include <iostream>#include <functional>void foo(int& a) { ++a;}void test_function(std::function...
c++开启一个简单的http响应
bind函数把一个本地的协议地址赋予一个套接字,对于网际协议。协议地址是32位de ip4或者128位的ip6与16位的tcp或者udp端口的组合。 if (result == SOCKET_ERROR) \/* 绑定失败 *\/ { closesocket(srv_soc); printf("[Web] Fail to bind, error = %d\\n", WSAGetLastError()); return -1; } result ...
vc++网络编程recvfrom函数问题?
1,创建套接字(socket)。2,将套接字绑定到本地地址和端口上(bind)。3,等待接受数据(recvfrom)。4,关闭套接字。#include <iostream.h> include <stdio.h> include <Winsock2.h> \/\/必须加载套接字的头文件,还必须在工程的链接处添加 Ws2_32.lib int main(){ WORD wVersionRequested...
计算机网络socket linux下用c或c++写
if (r == -1) { perror("bind(listen)"); return 0;} if (bTcp) { r = listen(s, SOMAXCONN);if (r == -1) { perror("listen()"); return 0;} }\/*end if*\/ \/*signal(SIGPIPE, SIG_IGN);*\/ return s;}\/*end do_listen*\/ void response(int sck, struct sockaddr_in ...
boost:ioservice run等待多久没有回调事件返回
include <boost\/bind.hpp> include <boost\/date_time\/posix_time\/posix_time.hpp> 首先,调整一下timer的持续时间,开始一个异步等待.显示,回调函数需要访问timer来实现周期运行,所以我们再介绍两个新参数 指向timer的指针 一个int*来指向计数器 void print(const asio::error& \/*e*\/,asio::deadline...
JQuery入门——用bind方法绑定事件处理函数应用介绍
1、bind()功能是为每个选择元素的事件绑定处理函数,其语法如下:bind(type,[data],fn)其中type为一个或多个类型的字符串,如click或change,也可以自定义;可以被type调用的类型包括blur、focus、load、resize、scroll、unload、click、dbclick、mousedown等事件。参数data是作为event.data属性值传递对象的...