1. 几种可调用对象(Callable Objects)

(1)普通函数指针类成员的函数指针

(2)具有operator()成员函数的类对象(仿函数)。如c++11中的std::function类模板,本质上就是一个仿函数

(3)可被转换为函数指针的类对象(需要重载类型转换操作符operator type(),其中type为目标类型:函数指针。这种写法与不带参的type operator()(void)效果等价)。

【编程实验】可调用对象示例

//test1.cpp

#include <iostream>
using namespace std; //1. 普通函数
void func(void)
{
} //2. 仿函数对象
struct Foo
{
void operator()(void)
{ }
}; //3. 可转换为函数指针的类
struct Bar
{
using fr_t = void(*)(void); //function return type: 函数返回值类型 static void func(void)
{
} //将类对象转化为函数指针。
//(本质上还是仿函数,只不过返回值是函数指针(fr_t)。
operator fr_t(void) //重载类型转换操作符,效果上等价于fr_t operator()(void)
{
return func;
}
}; //4. 类的成员函数
struct Test
{
int m;
void mem_func(void)
{ }
}; int main()
{
//1. 普通函数
void(*pfunc)(void) = &func;
pfunc(); //2.仿函数
Foo foo;
foo(); //3.可转换为函数指针的类
Bar bar;
bar(); //4.类成员函数指针
void(Test::*pmem_func)(void) = &Test::mem_func;
int Test::*pm = &Test::m; Test t;
(t.*pmem_func)();
t.*pm = ; return ;
}

2. 仿函数类的分析(如: binder2nd<T>、less<T>)

(1)以count_if算法的调用为例

  ①调用count_if函数时,要向其传入容器的相关迭代器以及第3个参数,该参数是一个判断表达式,在本例中是一个binder2nd类型的仿函数对象

  ②每次遍历时,会调用binder2nd仿函数对象的operator(),并向其传入(*first)参数。该对象内部保存着由外部传入的less仿函数对象的引用及该函数对象的第2个参数值40,它们分别保存在op变量和value变量中。

  ③在binder2nd仿函数对象的operator()中,会调用op仿函数 (less对象)并传入*first和40,从而可以判断*first和40的大小。

(2)相关源代码以说明

/***********************************************************************/
//以下两个类模板主要用于定义函数参数和返回值的类型。让子类可以回答
//函数适配器(adapter)可能向其询问的这两个问题。
//只有一个参数的函数类模板
template <class Arg, class Result>
struct unary_function {
typedef Arg argument_type; //参数类型
typedef Result result_type; //返回值类型
}; //两个参数的函数类模板
template <class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type; //第1个参数类型
typedef Arg2 second_argument_type; //第2个参数类型
typedef Result result_type; //返回值类型
}; /***********************************************************************/
//统计指定范围的元素个数的算法
template <class InputIter, class Predicate>
typename iterator_traits<InputIter>::difference_type
count_if(InputIter first, InputIter last, Predicate pred) {
typename iterator_traits<InputIter>::difference_type n = ; //计数器
for ( ; first != last; ++first)
if (pred(*first)) //如果元素带入pred判断的结果为true,计数器加1
++n;
return n;
} /***********************************************************************/
//仿函数对象:用于比较x和y的大小。x<y则返回真,否则假。
//注意:该类继承自binary_function类,表达他有两个参数和一个返回值。
template <class T>
struct less : public binary_function<T, T, bool>
{
bool operator()(const Tp& x, const T& y) const { return x < y; }
}; //仿函数类:用于将可调用对象(如函数)以及其参数保存并封装成一个类
//注意:该类继承自unary_function类,表示只有一个参数和返回值。
// binder2nd顾名思义就是要将参数绑定在op的第2个参数上,所以要求
// Operation这个类必须继承自binary_function。
template <class Operation>
class binder2nd
: public unary_function<typename Operation::first_argument_type,
typename Operation::result_type> {
protected:
Operation op; //可调用对象(如函数) //Operation类必须继承自binary_function类,才能回答下列关于第2个参数类型的提问。
typename Operation::second_argument_type value;//函数的第2个参数
public:
//构造函数
binder2nd(const Operation& x,
const typename Operation::second_argument_type& y)
: op(x), value(y) {}
typename Operation::result_type
operator()(const typename Operation::first_argument_type& x) const {
return op(x, value); //转向调用被保存对象的operator()函数
}
}; /***********************************************************************/
//辅助函数,让用户间接地,当然也更方便调用binder2nd(op,x);
//如果直接调用,如binder2nd<Operation>(less<int>(), 40)则还需要填写出Operation,根据
//binder2nd模板的定义,该值就是op的类型,此例中即less<int>的类型,这不好判断。
//而如果用以下的bind2nd函数,可以让编译器根据op(即less<int>)自动推导出Operation类型。
template <class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x)
{
typedef typename Operation::second_argument_type arg2_type;
return binder2nd<Operation>(op, arg2_type(x));
}

bind2nd函数模板、binder2nd类模板等

3. binder2nd类模板和bind2nd函数模板(重点)

(1)binder2nd类模板

  ①重载了operator()操作符,所以该类的对象是一个函数对象(仿函数)

  ②该类用于保存外部传入的函数(或仿函数)以及其参数。它是一个Wrapper类,用于包装和改造传入的函数(或仿函数),然后形成一个新的仿函数对象

  ③继承自unary_function模板,表示该类最终绑定外部函数及参数后,仍然是一个函数对象(仿函数)。但新函数对象与传入的函数相比,其参数个数减少为1个

(2)bind2nd函数模板

  ①bind2nd是一个函数模板,用于简化对binder2nd的操作。

  ②函数的返回值是一个binder2nd对象,该对象是个函数对象(仿函数),也是一个可调用对象。

(3)bind1st、bind2nd函数模板

  ①bind1st用于将参数绑定在被绑定函数的第1个参数上,返回新的函数对象。

  ②bind2nd用于将参数绑定在被绑定函数的第2个参数上,返回新的函数对象。

第10课 std::bind和std::function(1)_可调用对象的更多相关文章

  1. 第11课 std::bind和std::function(2)_std::bind绑定器

    1. 温故知新:std::bind1st和std::bind2nd (1)bind1st.bind2nd首先它们都是函数模板,用于将参数绑定到可调用对象(如函数.仿函数等)的第1个或第2个参数上. ( ...

  2. c++11特性与cocos2d-x 3.0之std::bind与std::function

    昨天同事让帮忙写一小功能,才发现cocos2d-x 3.0 和 cocos2d-x 3.0rc0 差别还是相当大的. 发现Label这一个控件,3.0就比rc0版本多了一个创建函数,更为关键的是3.0 ...

  3. std::bind和std::function

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

  4. 第12课 std::bind和std::function(3)_std::function可调用对象包装器

    1. std::function (1)首先是一个类模板,用于包装可调用对象.可以容纳除了类成员(函数)指针之外的所有可调用对象. (2)可以将普通函数,lambda表达式和函数对象类统一起来.尽管它 ...

  5. std::bind与std::ref, why and how

    首先解释下为什么有时候需要bind. 我们可以用bind从函数T add(T a, T b)造出个inc()来,即把b写死为1.这个例子本身比较傻,但有不傻的应用. template<typen ...

  6. 第19课 lambda vs std::bind

    一. std::bind (一)std::bind实现的关键技术 [编程实验]探索bind原理,实现自己的bind函数 #include <iostream> #include <t ...

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

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

  8. C++ 中std::function 、std::bind的使用和lambda的使用

    std::function是可调用对象的包装器:std::bind是将可点用对象和其参数一起进行绑定,且绑定后的结果可以使用std::function对象进行保存,并延迟调用到需要调用的时候: 在C+ ...

  9. C++ 11 std::function std::bind使用

    cocos new 出新的项目之后,仔细阅读代码,才发现了一句3.0区别于2.0的代码: auto closeItem = MenuItemImage::create( "CloseNorm ...

随机推荐

  1. c#实现RGB字节数组生成图片

    我是要用c#来实现,现在已经知道了rgb数组,那么如何快速生成一张图片呢? 其实这个话题并不局限于是rgb字节数组的顺序,只要你能对于上表示红.绿.蓝的值,就可以生成图片.知道了原理,做什么都简单了. ...

  2. 关于fit和transform

    Fit是对于数据进行拟合,所谓拟合,就是根据数据,计算获得数据里面的一些指标,比如均值,方差:下一步很多API都是需要这些参数来进行后续对数据的操作,比如下面要讲到的transform. Transf ...

  3. Hadoop HDFS DataNode 目录结构

    DataNode 目录结构 和namenode不同的是,datanode的存储目录是初始阶段自动创建的,不需要额外格式化. 1.    在/opt/module/hadoop-2.7.2/data/t ...

  4. MVC4.0,并完美结合Razor引擎

    本文主要解决“当前上下文不存在ViewBag”的问题, 在View视图实际使用过程中,如果引用不正确会提示“当前上下文不存在ViewBag”,首先需要引入“Microsoft.CSharp”类库 然后 ...

  5. http修改443端口,http 强制跳转https

    修改apache http/https 端口号 1.修改http的端口 打开$HTTPD_HOME/conf/httpd.conf文件,找到Listen,后面紧跟的是端口号,默认是80,把它修改为你想 ...

  6. DLL的晚绑定与早绑定

    调用DLL中的函数可分为早绑定与晚绑定! 早绑定是指在编译期就已经确定函数地址! 晚绑定是指在运行期动态加载dll,并根据查表的方式获取dll内exports函数的地址,由于早绑定比较简单,在此不再讲 ...

  7. Office CVE-2017-8570远程代码执行漏洞复现

    实验环境 操作机:Kali Linux IP:172.16.11.2 目标机:windows7 x64 IP:172.16.12.2 实验目的 掌握漏洞的利用方法 实验工具 Metaspliot:它是 ...

  8. 未找到路径“/Agent/SissQrTemplate/AddN”的控制器或该控制器未实现 IController。

    未找到路径“/Agent/SissQrTemplate/AddN”的控制器或该控制器未实现 IController. Controller 命名空间错误,应该是Areas.Agent.Controll ...

  9. Xshell5 评估过期,需要采购,不能使用

    Xshell5 评估过期,需要采购,不能使用 标签: Xshell linux 2017年10月10日 13:13:1029507人阅读 评论(9) 收藏 举报 版权声明:本文为博主原创文章,未经博主 ...

  10. How HipChat Stores And Indexes Billions Of Messages Using ElasticSearch And Redis[转]

    This article is from an interview with Zuhaib Siddique, a production engineer at HipChat, makers of  ...