c++ 11 bind function
std::function 和 std::bind
标准库函数bind()和function()定义于头文件中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。bind()接受一个函数(或者函数对象,或者任何你可以通过”(…)”符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”或重新组织的函数对象。(译注:顾名思义,bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的。)例如:
int f(int, char, double);
// 绑定f()函数调用的第二个和第三个参数,
// 返回一个新的函数对象为ff,它只带有一个int类型的参数
auto ff = bind(f, _1, ‘c’, 1.2);
int x = ff(7); // f(7, ‘c’, 1.2);
参数的绑定通常称为”Currying”(译注:Currying—“烹制咖喱烧菜”,此处意指对函数或函数对象进行加工修饰操作), “_1″是一个占位符对象,用于表示当函数f通过函数ff进行调用时,函数ff的第一个参数在函数f的参数列表中的位置。第一个参数称为”_1″, 第二个参数为”_2″,依此类推。例如:
int f(int, char, double);
auto frev = bind(f, _3, _2, _1); // 翻转参数顺序
int x = frev(1.2, ‘c’, 7); // f(7, ‘c’, 1.2);
此处,auto关键字节约了我们去推断bind返回的结果类型的工作。
我们无法使用bind()绑定一个重载函数的参数,我们必须显式地指出需要绑定的重载函数的版本:
int g(int);
double g(double); auto g1 = bind(g, _1); // 错误:调用哪一个g() ?
// 正确,但是相当丑陋
auto g2 = bind( (double(*)(double))g, _1);
bind()有两种版本:一个如上所述,另一个则是“历史遗留”的版本:你可以显式地描述返回类型。例如:
auto f2 = bind<int> (f, 7, ‘c’, _1); // 显式返回类型
int x = f2(1.2); // f(7, ‘c’, 1.2);
第二种形式的存在是必要的,并且因为第一个版本((?) “and for a user simplest “,此处请参考原文))无法在C++98中实现。所以第二个版本已经被广泛使用。
function是一个拥有任何可以以”(…)”符号进行调用的值的类型。特别地,bind的返回结果可以赋值给function类型。function十分易于使用。(译注:更直观地,可以把function看成是一种表示函数的数据类型,就像函数对象一样。只不过普通的数据类型表示的是数据,function表示的是函数这个抽象概念。)例如:
// 构造一个函数对象,
// 它能表示的是一个返回值为float,
// 两个参数为int,int的函数
function<float (int x, int y)> f; // 构造一个可以使用"()"进行调用的函数对象类型
struct int_div {
float operator() (int x, int y) const
{ return ((float)x)/y; };
}; f = int_div(); // 赋值
cout<< f(5,3) <<endl; // 通过函数对象进行调用
std::accumulate(b, e, 1, f); // 完美传递
成员函数可被看做是带有额外参数的自由函数:
struct X {
int foo(int);
}; // 所谓的额外参数,
// 就是成员函数默认的第一个参数,
// 也就是指向调用成员函数的对象的this指针
function<int (X*, int)> f;
f = &X::foo; // 指向成员函数 X x;
int v = f(&x, 5); // 在对象x上用参数5调用X::foo()
function<int (int)> ff = std::bind(f, &x, _1); // f的第一个参数是&x
v = ff(5); // 调用x.foo(5)
function对于回调函数、将操作作为参数传递等十分有用。它可以看做是C++98标准库中函数对象mem_fun_t, pointer_to_unary_function等的替代品。同样的,bind()也可以被看做是bind1st()和bind2nd()的替代品,当然比他们更强大更灵活。
参考:
- Standard: 20.7.12 Function template bind, 20.7.16.2 Class template function
- Herb Sutter:Generalized Function Pointers
.
August 2003. - Douglas Gregor:
Boost.Function
. - Boost::bind
(翻译:dabaitu)
boost::function<void()> f1;//无参数,无返回值
头文件:boost/function.hpp
#include<iostream>
#include<boost/function.hpp>
#include<boost/bind.hpp>
#include<string>
using namespace std; class Foo
{
public:
void methodA() { cout<<"methodA"<<endl;}
void methodInt(int a){ cout<<"methodInt:"<<a<<endl;}
void methodString(const string& str){ cout<<"methodStirng:"<<str<<endl;}
};
class Bar
{
public:
void methodB(){ cout<<"methodB"<<endl;}
}; int main()
{
boost::function<void()> f1;
Foo foo;
f1=boost::bind(&Foo::methodA,&foo);
f1();//foo.methodA(); Bar bar;
f1=boost::bind(&Bar::methodB,&bar);
f1(); f1=boost::bind(&Foo::methodInt,&foo,);
f1();//foo.methodInt(42); boost::function<void(int)> f2;
f2=boost::bind(&Foo::methodInt,&foo,_1);
f2(); }
c++中取成员函数的地址,比如:
cout<<&Foo::methodA<<endl;
cout<<&Foo::methodInt<<endl;
cout<<&Foo::methodString<<endl;
上面都输出1.
用一个实际代码来说明。
- class A
- {
- public:
- staticvoid staticmember(){cout<<"static"<<endl;} //static member
- void nonstatic(){cout<<"nonstatic"<<endl;} //nonstatic member
- virtualvoid virtualmember(){cout<<"virtual"<<endl;};//virtual member
- };
- int main()
- {
- A a;
- //static成员函数,取得的是该函数在内存中的实际地址,而且因为static成员是全局的,所以不能用A::限定符
- void(*ptrstatic)()=&A::staticmember;
- //nonstatic成员函数 取得的是该函数在内存中的实际地址
- void(A::*ptrnonstatic)()=&A::nonstatic;
- //虚函数取得的是虚函数表中的偏移值,这样可以保证能过指针调用时同样的多态效果
- void(A::*ptrvirtual)()=&A::virtualmember;
- //函数指针的使用方式
- ptrstatic();
- (a.*ptrnonstatic)();
- (a.*ptrvirtual)();
- }
可以参考《C++ Primer(3rd)》第532页13.6指向类成员的指针一节~
1.一个指向外部函数的指针声明为:
- void(*pf)(char*,constchar*);
- void strcpy(char* dest,constchar* source);
- pf=strcpy;
2.一个指向类A成员函数的指针声明为:
- void(A::*pmf)(char*,constchar*);
声明的解释是:pmf是一个指向A成员函数的指针,返回无类型值,函数带有二个参数,参数的类型分别是char * 和 const char *。除了在星号前增加A:: ,与声明外部函数指针的方法一样。
3.给成员指针赋值的方法是将函数名通过指针符号&赋予指针名。
如下所示:
- class A
- {
- public:
- void strcpy(char*,constchar*);
- void strcat(char*,constchar*);
- };
- pmf =&A::strcpy;
之前的:
typedef void (Foo::* FuncA)(int);
int main()
{
FuncA p1=&Foo::methodInt;
Foo obj;
(obj.*p1)(5);
C++指向类成员函数的指针详细解析
首先 函数指针是指向一组同类型的函数的指针;而类成员函数我们也可以相似的认为,它是指向同类中同一组类型的成员函数的指针,当然这里的成员函数更准确的讲应该是指非静态的成员函数。前者是直接指向函数地址的,而后者我们从字面上也可以知道 它肯定是跟类和对象有着关系的。
函数指针实例:
typedef int (*p)(int,int);//定义一个接受两个int型且返回int型变量的函数指针类型
int func(int x,int y)
{
printf("func:x=%d,y=%d/n",x,y);
return (x<y?x:y);
}
int main()
{
p fun=func;//定义函数指针并给它赋上一个函数指针
cout<<"min:"<<(*fun)(,)<<endl;//为什么*fun需要用()扩起来呢?因为*的运算符优先级比()低,如果不用()就成了*(fun())
return ;
}
而“指向类成员函数的指针”却多了一个类的区别:
class A
{
public:
int func(int x,int y)
{
printf("A::func:x=%d,y=%d/n",x,y);
return (x<y?x:y);
}
};
typedef int (A::*p)(int,int);//指针名前一定要加上所属类型类名 A::的限定
int main()
{
p fun=&A::func;
A a; //因为成员函数地址的解引用必须要附驻与某个对象的地址,所以我们必须创建某个对象。
cout<<"min:"<<(a.*fun)(,)<<endl;
return ;
}
嘿嘿。。只是用起来 .* 感觉怪怪滴。
接下来 我们可以再扩展一下下:
#include <tchar.h>
#include <iostream>
#include <stdio.h>
using namespace std;
class A
{
public:
int func1(int x,int y)
{
printf("A::func:x=%d,y=%d/n",x,y);
return (x<y?x:y);
}
virtual int func2(int x,int y)
{
printf("A::func:x=%d,y=%d/n",x,y);
return (x>y?x:y);
}
};
class B:public A
{
public:
virtual int func2(int x,int y)
{
printf("B::func:x=%d,y=%d/n",x,y);
return (x+y);
}
};
typedef int (A::*p)(int,int);//指针名前一定要加上所属类型类名 A::的限定
typedef int (B::*p0)(int,int);
int main()
{
A a; //因为成员函数地址的解引用必须要附驻与某个对象的地址,所以我们必须创建某个对象。 p fun=&A::func1;
cout<<(a.*fun)(,)<<endl;
cout<<(b.*fun)(,)<<endl<<endl;
fun=&A::func2;
cout<<(a.*fun)(,)<<endl;//请注意这里调用的是虚函数,嘿嘿 还真神奇 类成员函数指针也支持多态。
cout<<(b.*fun)(,)<<endl<<endl;
//fun=&B::func2; //这样式错误滴,因为不存在派生类的"指向类成员函数的指针"到基类的"指向类成员函数的指针"的隐式转换
fun=(int (A::*)(int,int))&B::func2;//应该进行强制转换
cout<<(a.*fun)(,)<<endl;
cout<<(b.*fun)(,)<<endl<<endl; p0 fun0=&B::func2;
cout<<(a.*fun)(,)<<endl;
cout<<(b.*fun)(,)<<endl<<endl; fun0=&A::func2; //正确,因为这里进行了隐式转换
cout<<(a.*fun)(,)<<endl;
cout<<(b.*fun)(,)<<endl<<endl;
//从上面我们不难发现 指向类成员函数的指针基类和派生类的关系和指向类对象的指针基类和派生类的关系完全相反,
//基类成员函数的布局被认为是派生类成员函数布局的一个子集
return ;
}
接下 是有关模板类的类成员函数指针的使用
实例如下:
#include <tchar.h>
#include <iostream>
#include <stdio.h>
using namespace std;
class A
{
public:
int func(int x,int y)
{
printf("A::func : x=%d,y=%d/n",x,y);
return (x<y?x:y);
}
};
class B
{
public:
int func(int x,int y)
{
printf("B::func : x=%d,y=%d/n",x,y);
return (x>y?x:y);
}
};
template<class T>
class C
{
public:
T c;
void Print()
{
int (T::*p)(int,int)=&T::func;
(c.*p)(,);
}
};
int main()
{
C<A> ca;
C<B> cb;
ca.Print();
cb.Print();
return ;
}
从上面 可以很清晰地看到。。其实它和普通的模板没有什么区别。。只不过将限定名称该为参数名酒OK啦。。。
更多;
http://www.vckbase.com/index.php/wv/1514
c++ 11 bind function的更多相关文章
- 使用C++11的function/bind组件封装Thread以及回调函数的使用
之前在http://www.cnblogs.com/inevermore/p/4008572.html中采用面向对象的方式,封装了Posix的线程,那里采用的是虚函数+继承的方式,用户通过重写Thre ...
- boost之bind,function,signal总结
boost里的bind,function,signal三个组件都是对用函数做参数(其他算法也用函数做参数),对函数的某一项进行操作. bind主要是对函数参数的作用. function主要是对函数地址 ...
- 应该用bind+function取代虚函数吗?
用bind+function取代虚函数在好几年前就有人提出了,曾引起广泛的讨论,有支持的有反对的,可能赞成的人占大多数.这个话题挺有趣,本来是作为技术沙龙的开放性话题来讨论的,由于时间关系并没有讨论. ...
- boost bind function用法说明
目录(?)[+] 1 bind/function 引 (1)头文件 bind函数#include <boost/bind.hpp> function使用头文件#include <bo ...
- 借助boost bind/function来实现基于对象编程。
boost bind/function库的使用: 替换了stl中mem_fun,bind1st,bin2nd等函数.用户注册回调函数需要利用boost/bind转化成库中boost/function格 ...
- 利用C++11的function和bind简化类创建线程
问题引出 当在类中需要创建线程时,总是因为线程函数需要定义成静态成员函数,但是又需要访问非静态数据成员这种需求,来做若干重复性的繁琐工作.比如我以前就经常定义一个静态成员函数,然后定一个结构体,结构体 ...
- C++ 11 std::function std::bind使用
cocos new 出新的项目之后,仔细阅读代码,才发现了一句3.0区别于2.0的代码: auto closeItem = MenuItemImage::create( "CloseNorm ...
- c++11——std::function和bind绑定器
c++11中增加了std::function和std::bind,可更加方便的使用标准库,同时也可方便的进行延时求值. 可调用对象 c++中的可调用对象存在以下几类: (1)函数指针 (2)具有ope ...
- C++11 中function和bind以及lambda 表达式的用法
关于std::function 的用法: 其实就可以理解成函数指针 1. 保存自由函数 void printA(int a) { cout<<a<<endl; } std:: ...
随机推荐
- TCP/IP笔记(八)应用层协议
TCP/IP的应用层涵盖了OSI参考模型中第5.第6.第7层的所有功能,不仅包含了管理通信连接的会话层功能.转换数据格式的标识层功能,还包括与对端主机交互的应用层功能在内的所有功能. 利用网络的应用程 ...
- The Definitive Guide To Django 2 学习笔记(七) 第四章 模板 (三)使用模板系统
接下来,我们开始学习如何使用模板系统,但我们并不和前面说的View相结合,我们的这里的目的是展示模板系统是如何独立于Django框架运行的.下面是在pyhon代码中使用Django模板系统的基础例子: ...
- 目录视图摘要视图订阅 基于Extjs开发不允许为空的文本框提示及相应的验证错误提示(转)
原文地址:http://blog.csdn.net/kunoy/article/details/8007585 本文主要解决问题: 1.区分哪些文本框不允许为空,很多网站都采用在文本框后加*号,ext ...
- 基于WebBrowser 的爬虫程序
WebBrowser的属性和事件 WebBrowser 如何跳转页面 web.Navigate(""); WebBrowser 如何循环跳转获取页面内容 bool loading ...
- 获取一个Assembly中的命名空间列表
通过System.Reflection.Assembly类中提供的方法和属性不能直接获取组件中的命名空间列表.但有方法可以直接获得Assembly中的所有类型,我们便可以通过获取的类型来得到命名空间名 ...
- Ubuntu上安装与配置JDK1.8
Ubuntu上安装与配置JDK1.8 一.下载 下载JDK,由于是Ubuntu. 所以去官网下载tar.gz格式的就可以(ubuntu使用浏览器下载网速比較慢,所以推荐到window上下载好). ht ...
- 利用jsonrpc技术包装uiautomator
昨天一天在网上搜索解决上一篇文章中的exception: monkeyrunner内置uiautomator出错的原因 尽管没找到解决办法.可是让我无意中发现了一个好工具,比sl4a更好用的工具.直接 ...
- android发送邮件
众所周知,在Android中调用其他程序进行相关处理,几乎都是使用的Intent,所以,Email也不例外. 在Android中,调用Email有三种类型的Intent: Intent.ACT ...
- CentOS 同步时间
来源:http://www.ctusky.com/16/0497/ 用date查看系统当前时间,date -R 可查看时区. CentOS 同步时间由ntp服务提供,可以用"yum inst ...
- 【BZOJ4704】旅行 树链剖分+可持久化线段树
[BZOJ4704]旅行 Description 在Berland,有n个城堡.每个城堡恰好属于一个领主.不同的城堡属于不同的领主.在所有领主中有一个是国王,其他的每个领主都直接隶属于另一位领主,并且 ...