std::bind

bind是对C++98标准中函数适配器bind1st/bind2nd的泛化和增强,可以适配任意的可调用对象,包括函数指针、函数引用、成员函数指针和函数对象。

bind接受的第一个参数必须是一个可调用的对象f,可以是函数、函数指针、函数对象和成员函数指针,之后接受的参数的数量必须与f的参数数量相等,这些参数将被传递给f作为入参。

绑定完成后,bind会返回一个函数对象,它内部保存了f的拷贝,具有operator(),返回值类型被自动

推导为f的返回值类型。反生调用时,这个函数对象将把之前存储的参数转发给f完成调用。

如:

int Add(int num1, int num2)
{
return (num1 + num2);
} Add(1,2);
//等价于一个具有无参operator()的bind函数对象调用
std::bind(&Add,1,2)();

这是bind最简单的形式。bind表达式存储了Add和参数1,2的拷贝,产生了一个临时的函数对象。因为Add接受两个参数,而1,2都是实参,因此临时函数对象将具有一个无参的operator()。当operator()调用发生时函数对象把1、2的拷贝传递给Add,完成真正的调用。

bind的真正威力在与占位符,_1 _2 _3 ...,(为了避免与boost库的占位符冲突,标准占位符定义在std::placeholders名字空间,使用时:std::placeholders::_1),占位符可以取代bind中参数的位置,在发生函数调用时才接受真正的参数。

占位符的名字表示它在调用时中的顺序,而在绑定式中没有顺序要求。如下:

int Sub(int num1,int num2)
{
return (num1 - num2);
}
std::bind(&Sub,std::placeholders::_1,std::placeholders::_2)(2,1);
//等价于
Sub(2,1);
std::bind(&Sub,std::placeholders::_2,std::placeholders::_1)(2,1);
//等价于
Sub(1,2);

bind详细用法:

//普通全局函数
void Out( int & elem)
{
std::cout << elem << " ";
} //类
template<typename T>
class Print
{
public:
Print(const char * prefix = "")
: _prefix(prefix)
, _printNum(0)
{
}
//非静态成员函数
void PrintElem(const T & elem)
{
_printNum++;
if (_printNum <= 1)
{
cout << "\n" << _prefix << ": ";
}
cout << elem << " ";
}
//静态成员函数
static void static_fun()
{
std::cout << "\nstatic func!";
}
private:
string _prefix;
size_t _printNum;
}; int arr[] = {1,2,1,3,4,8,9,8};
vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));

//绑定普通函数
std::for_each(v.begin(),v.end(),std::bind(&Out,std::placeholders::_1)); //绑定类的非静态成员函数
//第一个占位符的位置必须是一个类的实例、引用或指针
Print<int> print("bind member function");
std::for_each(v.begin(),v.end(),
std::bind(&(Print<int>::PrintElem),&print,std::placeholders::_1));
//注:必须在成员函数前加上取地址操作符&,表明这是一个成员函数指针,否则会无法通过编译。 //绑定静态成员函数 与绑定全局函数没有区别
std::function<void(void)> ff = std::bind(&Print<int>::static_fun);
ff();

绑定函数对象:

bind可以绑定任意的函数对象,包括标准库中的所有预定义的函数对象。

如果函数对象有内部类型定义result_type,那么bind可以自动推导出返回值类型,用法与绑定普通函数一样。否则,需要在绑定形式上做出变动,用模版参数指明返回类型。

bind<result_type>(functiontor, ...)

标准库中大部分函数对象都有result_type定义,因此不需要特别的形式。

//绑定预定义的函数对象
std::transform(v.begin(),v.end(),v.begin(),
std::bind(std::plus<int>(),std::placeholders::_1,10)); //绑定函数对象 //绑定自定义的函数对象
//要想bind 绑定自定义的函数对象,必须提供一些型别的成员来反映其参数和返回值的型别,
//为了方便,可以继承 binary_function等
template<typename T1, typename T2>
struct fopow : public std::binary_function<T1,T2,T1>
{
T1 operator() (T1 base, T2 exp) const
{
return std::pow(base,exp);
}
};
std::transform(v.begin(),v.end(),v.begin(),
std::bind(fopow<double,int>(),std::placeholders::_1,2)); //自己定义result_type
template<typename T>
struct MyPlus
{
typedef T argument_type;
typedef T result_type;
result_type operator() (const argument_type & arg1, const argument_type & arg2) const
{
return (arg1 - arg2);
}
}; std::function<int(int)> f = std::bind(MyPlus<int>(),std::placeholders::_1,10);
std::transform(v.begin(),v.end(),v.begin(),f);

补充:

//binary_function原型

template<class _Arg1,
class _Arg2,
class _Result>
struct binary_function
{ // base class for binary functions
typedef _Arg1 first_argument_type;
typedef _Arg2 second_argument_type;
typedef _Result result_type;
};

关于std::function,可以参考C++11中的std::function这篇文章。

std::bind学习的更多相关文章

  1. C++11学习笔记之三lamda表达式,std::function, std::bind

    //lamda //first lamda [] {}; // second lamda []() //or no need () when paramater is null { std::cout ...

  2. std::bind 详解及参数解析

    // Bind_std_function.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> ...

  3. std::bind技术内幕

    引子 最近群里比较热闹,大家都在山寨c++11的std::bind,三位童孩分别实现了自己的bind,代码分别在这里: 木头云的实现 mr.li的实现 null的实现,null的另一个版本的实现 这些 ...

  4. C/C++ C++ 11 std::bind()

    { #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA ...

  5. C++11之std::function和std::bind

    std::function是可调用对象的包装器,它最重要的功能是实现延时调用: #include "stdafx.h" #include<iostream>// std ...

  6. std::bind和std::function

    std::bind 用于绑定一个函数,返回另外一种调用方式的函数对象 ,可以改变参数顺序 和个数,特别是在多线程的程序中,经常用它将函数进行包装,然后打包发送给工作线程,让工作线程去执行我们的任务. ...

  7. std::function,std::bind

    std::function 和 std::bind 标准库函数bind()和function()定义于头文件中(该头文件还包括许多其他函数对象),用于处理函数及函数参数.bind()接受一个函数(或者 ...

  8. std::function,std::bind复习

    #include <iostream> #include <functional>//std::bind返回函数对象 void fun1(int a, int b) { std ...

  9. C++11 std::bind std::function 高级使用方法

    从最基础的了解,std::bind和std::function /* * File: main.cpp * Author: Vicky.H * Email: eclipser@163.com */ # ...

随机推荐

  1. HttpWebRequest 基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系

    请求对象前加入 ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate; 然后实现该方法 ...

  2. Mybatis常考面试题汇总(附答案)

    1.#{}和${}的区别是什么? #{}和${}的区别是什么? 在Mybatis中,有两种占位符 #{}解析传递进来的参数数据 ${}对传递进来的参数原样拼接在SQL中 #{}是预编译处理,${}是字 ...

  3. OpenGL着色器入门简介

    说明:本文翻译自LearnOpengl经典教程,OpenGL着色器基础介绍的比较通俗易懂,特总结分享一下! 为什么要使用着色器?我们知道,OpenGL一般使用经典的固定渲染管线来渲染对象,但是随着Op ...

  4. windows下设置PHP环境变量

    1.找到“高级系统设置”(二选一的方法找到环境变量) ① 我的电脑-属性-高级-环境变量 ②win8,10 直接在搜索框搜 “查看高级系统设置”-环境变量 2.找到变量"Path" ...

  5. ubuntu使任何地方右键都能打开terminal

    ubuntu下安装terminal,在任何地方右键都可以快速的打开termial sudo apt-get install nautilus-open-terminal 重启电脑

  6. MFMailComposeViewController发送邮件的实例

    本文转载至 http://blog.csdn.net/liufeng520/article/details/7585140   iPhone API已经提供了系统写邮件界面的接口,使用MFMailCo ...

  7. Oracle误删除数据的恢复方法(转)

    来源:原创网站北京北亚数据恢复中心,转载须注明出处. 学习数据库时,我们只是以学习的态度,考虑如何使用数据库命令语句,并未想过工作中,如果误操作一下,都可能导致无可挽回的损失.当我在工作中真正遇到这些 ...

  8. linux部署的flask项目配置static

    环境: Python2.7 flask nginx linux的系统是Ubantu Python:我的是linux已经有的. flask:pip install flask nginx:sudo ap ...

  9. 队列Queue、栈LifoQueue、优先级队列PriorityQueue

    队列:队列是先进先出. import queue q = queue.Queue() q.put(1) q.put(2) q.put(3) q.put(4) print(q.get()) print( ...

  10. XML5个转义符:<,>,&,”,©;的转义字符分别如下: &lt; &gt;&amp; &quot; &apos;

    XML5个转义符:<,>,&,”,©;的转义字符分别如下: < >& " &apos;             $search = array ...