1. 5种形式

可调用对象有5种形式,类型各不同:

形式 解释
函数 返回值类型和实参类型
函数指针 返回值类型和实参类型
lambda表达式 类类型
bind创建的对象 todo
重载了函数调用运算符的类 类类型

2. 虽然可调用对象类型不同,但是调用形式可以一样

调用形式指明了调用返回的类型以及传递给调用的实参类型。不同的可调用对象可能具有相同的调用形式。

eg. 类型都为int(int, int)

// ordinary function
int add(int i, int j) { return i + j; }//lambda表达式,其产生一个未命名的函数对象类
auto mod = [](int i, int j) { return i % j; };// function-object class
struct divide
{int operator()(int denominator, int divisor){return denominator / divisor;}
};//调用代码
//使用map映射
map<string,function<int(int,int)> > binops;
binops.insert({"+", add});
//error,不能将mode或divide insert到binope中,因为他们类型不是函数指针
binops.insert({"%", mod});

有个问题:不能统一调用

3. 如何统一调用?

标准库function类型:标准库function类型是一个模板,定义在头文件functional中,用来表示对象的调用形式。
使用时需要创建一个具体的function类型。(必须提供其所表示的对象的调用形式)

操作 解释
function f; f是一个用来存储可调用对象的空function,这些可调用对象的调用形式应该与类型T相同。
function f(nullptr); 显式地构造一个空function
function f(obj) 在f中存储可调用对象obj的副本
f 将f作为条件:当f含有一个可调用对象时为真;否则为假。
定义为function的成员的类型f(args) 调用f中的对象,参数是args
result_type 该function类型的可调用对象返回的类型
argument_type 当T有一个或两个实参时定义的类型。
first_argument_type 第一个实参的类型
second_argument_type 第二个实参的类型

eg. function<int(int, int)>

function<int(int,int)> f1=add;  //函数指针
function<int(int,int)> f2=divide();  //函数对象类的指针
function<int(int,int)> f3=[](int i,int l){return i*j;};  //lambdacout << f1(4,2) << endl;   // prints 6
cout << f2(4,2) << endl;   // prints 2
cout << f3(4,2) << endl;   // prints 8

eg2.

//使用map映射
map<string,function<int(int,int)> > binops={{"+",add},  //函数指针{"-",std::minus<int>()},  //标准库函数对象{"/",divide()},  // 用户定义的函数对象{"*",[](int i,int j){return i*j;}},  //未命名的lambda{"%",mod} //已命名的lambda对象
};//这个时候insert是可以的
binops.insert( {"+", add} ); //函数指针
binops.insert( {"/",divide()} );  //函数对象
binops.insert( {"%", mod} );  //lambda表达式
binops.insert({"+"},[](int a,in b){return add(a,b);});//lambda表达式
binops.insert({ "add" , [](int a, int b) {return add(a, b); } });//lambda表达式cout << binops["+"](10, 5)<<endl;//调用add(10, 5)
cout << binops["-"](10, 5) << endl;
cout << binops["/"](10, 5) << endl;   //使用divide对象调用括号运算符
cout << binops["*"](10, 5) << endl;
cout << binops["%"](10, 5) << endl;//调用lambda函数对象
cout << binops["add"](10, 5) << endl;//调用lambda函数对象

3.1 不能直接将重载函数的名字存入 function 类型的对象中,这样做会产生二义性错误。

int add(int i,int j){return i + j;}
Sales_data add(const Sales_data&,const Sales_data&);
map<string,funciton<int(int,int)>> binops;
binops.insert({"+",add});        //错误,不能区分是哪个add

3.2 解决方法

存储函数指针而非函数名字:

int (*fp) (int,int) = add;
binops.insert("add",fp);  //正确,fp指向正确的add版本
  • C++11新标准库中的function类与旧版本中的unary_function和binary_function没有关系,后两个类已经被bind函数代替。

【引用】

[1] 代码functionObject.h

C++ Primer 5th笔记(chap 14 重载运算和类型转换)可调用对象与function相关推荐

  1. C++ Primer 5th笔记(chap 14 重载运算和类型转换)二义性类型转换

    1. 在两种情况下会产生二义性转换歧义: 1.1 A类定义了一个接受B类对象的转换构造函数,同时B类定义了一个转换目标是A类的类型转换运算符. struct B; struct A {A() = de ...

  2. C++ Primer 5th笔记(chap 14 重载运算和类型转换)函数调用运算符

    1. 定义 如果类定义了调用运算符(重载了函数调用运算符),则该类的对象被称作函数对象(function object),可以像使用函数一样使用该类的对象, eg. struct absInt{int ...

  3. C++ Primer 5th笔记(chap 14 重载运算和类型转换)递增和递减运算符

    并不要求递增和递减运算符一定是类的成员函数,但是因为这个运算符改变的正好是所操作的对象的状态,所以建议将它们设为成员函数. 为了和内置版本保持一致,前置运算符应该返回递增或递减后对象的引用. 为了和内 ...

  4. C++ Primer 5th笔记(chap 14 重载运算和类型转换)重载运算概述

    1. 定义 重载运算是具有特殊名字的函数,它们的名字由关键字operator和其后要定义的运算符号组成. 2. 运算符表 2.1 可重载运算符 运算符类型 运算符种类 双目算术运算符 + (加),-( ...

  5. C++ Primer 5th笔记(chap 14 重载运算和类型转换)函数匹配与重载运算符

    如果一个类既提供了转换目标是算术类型的类型转换,也提供了重载的运算符,则将会遇到重载运算符与内置运算符的二义性问题. 如果a是一种类型,表达式 a sym b 可能是: //不能通过调用形式来区分当前 ...

  6. C++ Primer 5th笔记(chap 14 重载运算和类型转换)lambda函数对象

    1. 定义 lambda是函数对象:编写一个lambda后,编译器会将该表达式转换成一个未命名类的未命名对象,类中含有一个重载的函数调用运算符. eg. stable_sort(words.begin ...

  7. C++ Primer 5th笔记(chap 14 重载运算和类型转换)成员运算符

    成员运算符分为两种: 解引用运算符* 箭头运算符-> 设计准则 箭头运算符必须是类的成员. 解引用运算符通常也是类的成员,尽管并非必须如此. 重载的箭头运算符必须返回类的指针或者自定义了箭头运算 ...

  8. C++ Primer 5th笔记(chap 14 重载运算和类型转换)算术和关系运算符

    运算符 双目算术运算符 + (加),-(减),*(乘),/(除),% (取模) 关系运算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),> ...

  9. C++ Primer 5th笔记(chap 14 重载运算和类型转换)类类型转换

    1. 定义 类型转换运算符:(既然一个类类型可以由实参类型对象隐式转换而来,那么)一个类类型的值也可以转换成其它类型 形式 : operator type() const type 表示某种类型,类型 ...

最新文章

  1. Python核心编程笔记---- print
  2. 学Java还是Python?一张图告诉你!
  3. iOS 9音频应用播放音频之音量设置与声道设置
  4. 统计元音(格式控制)
  5. 危害网络安全或入信用“黑名单”
  6. php后台富文本编辑器的内容调用到前端小程序页面的一些显示问题,如:nbsp;
  7. 基于Nexys4DDR的数字时钟设计
  8. (六)将样式转换模型从TensorFlow转换为TensorFlow Lite
  9. PoolTogether 奖池开奖一名用户赢得 43,760 美元,本金仅为 73 美元
  10. linux发布成服务,linux服务简单部署
  11. 三元组顺序表表示的稀疏矩阵加法_知识表示学习记录(1)
  12. 增长战略五大维度:单点突破、由内而外、锚点绑定、群体延伸、圈层建设
  13. 【计算机体系结构实验】指令调度和延迟分支
  14. Win10 / 11新电脑最简单跳过联网激活和使用本地账户登录方法
  15. 8000 sentences of oral English(four)
  16. Danar程序员之家在CSDN安家落户啦
  17. C语言程序设计实践题,2020年C语言程序设计实践实验题目.doc
  18. 苹果AppStore应用商店生存之道:国内iOS开发者创业经验分享(三)
  19. centos7安装配置yum软件仓库
  20. 虚拟机架设传奇3服务器,WIN8安装虚拟机玩传奇3教程-转

热门文章

  1. 第十一届青少年蓝桥杯国赛真题精选 - 编程题
  2. Python 实现简单的石头剪刀布小游戏
  3. jQuery-基本选择器的种类
  4. java基础求三角形的面积
  5. Java 洛谷 P1307 数字反转
  6. 中南大学计算机085403,What?这些个专业改考数一英一了!
  7. AI公开课:19.04.10颜水成—360副总裁《人工智能:观察与实践》课堂笔记以及个人感悟—191017再次更新
  8. ML之LoRBaggingRF:依次利用Bagging、RF算法对泰坦尼克号数据集 (Kaggle经典案例)获救人员进行二分类预测——模型融合
  9. JAVA_OA(bug篇)(一):SpringMVC的bug1
  10. 《疯狂JAVA讲义》笔记1