C++标准库:可调用对象与 function
发布日期:2021-05-07 06:34:58 浏览次数:21 分类:精选文章

本文共 2467 字,大约阅读时间需要 8 分钟。

本文为《C++ Primer》的读书笔记

目录

可调用对象与调用形式

  • C++ 中有几种可调用的对象: 函数、函数指针、lambda 表达式、bind 创建的对象以及重载了函数调用运算符的类
  • 和其他对象一样, 可调用的对象也有类型。例如, 每个 lambda 有它自己唯一的(未命名)类类型; 函数及函数指针的类型则由其返回值类型和实参类型决定, 等等

不同类型可能具有相同的调用形式

  • 然而, 两个不同类型的可调用对象却可能共享同一种 调用形式(callsignature)。调用形式指明了调用返回的类型以及传递给调用的实参类型。一种调用形式对应一·个函数类型, 例如:
int(int, int)
  • 对于几个可调用对象共享同一种调用形式的情况,有时我们会希望把它们看成具有相同的类型。例如:
// 普通函数int add(int i, int j) {    return i + j; }// lambda, 其产生一个未命名的函数对象类auto mod = [](int i, int j) {    return i % j; };// 函数对象类struct divide {   	int operator() (int denominator, int divisor) {   		return denorninator / divisor;	};};
  • 上面这些可调用对象尽管它们的类型各不相同, 但是共享同一种调用形式:
int (int, int)
  • 我们可能希望使用这些可调用对象构建一个简单的桌面计算器。为了实现这一目的,需要定义一个函数表 (function table) 用于存储指向这些可调用对象的 “指针”。当程序需要执行某个特定的操作时, 从表中查找该调用的函数
  • 函数表很容易通过 map 来实现。对于此例来说, 我们使用一个表示运算符符号的 string 对象作为关键字;使用实现运算符的函数作为值
  • 假定我们的所有函数都相互独立, 并且只处理关于 int 的二元运算, 则 map 可以定义成如下的形式:
// 构建从运算符到函数指针的映射关系, 其中函数接受两个 int、返回一个 intmap
binops;// 将 `add` 的指针添加到 `binops` 中binops.insert({ "+", add});
  • 但是我们不能将mod或者divide存入binops。问题在于mod是个 lambda 表达式, 而每个 lambda 有它自己的类类型, 该类型与存储在 binops 中的值的类型不匹配

标准库 function 模板类

#include 

在这里插入图片描述


  • 下面的 function 类型表示接受两个int、返回一个int的可调用对象。甚至只要可调用对象的参数和返回类型能够隐式转化为 int 即可
function
function
f1 = add; // 函数指针function
f2 = divide(); // 函数对象类的对象function
f3 = [] (int i, int j) // lambda { return i * j; };cout << f1(4,2) << endl; cout << f2(4,2) << endl;cout << f3(4,2) << endl;
  • 使用这个 function 类型我们可以重新定义 map:
map
> binops = { { "+", add}, // 函数指针 { "-", std::minus
()}, // 标准库函数对象 { "I", divide()}, // 用户定义的函数对象 { "*", [](int i, int j) { return i * j; }}, // 未命名的lambda { "%", mod}}; // 命名了的 lambda 对象};
binops["+"](10, 5); //调用 add(10, 5)binops["-"](10, 5); //使用 minus
对象的调用运算符binops["/"](10, 5); //使用 divide 对象的调用运算符binops["*"](10, 5); //调用 lambda 函数对象binops["%"](10, 5); //调用 lambda 函数对象int a, b;string op;cin >> a >> op >> b;cout << binops[op](a, b) << endl;

重载函数 与 function

  • 我们不能(直接)将重载函数的名字存入function类型的对象中:
int add(int i, int j) {    return i + j; }Sales_data add(const Sales_data&, const Sales_data&);map
> binops;binops.insert( { "+", add} ); //错误: 哪个add?
  • 解决上述二义性问题的一条途径是存储函数指针而非函数的名字
int (*fp)(int, int) = add; 	// 指针所指的 add 是接受两个int 的版本binops.insert({   "+", fp}); 	// 正确: fp 指向一个正确的 add 版本
  • 同样, 我们也能使用 lambda 来消除二义性:
// 正确:使用lambda 未指定我们希望使用的add版本binops.insert({   "+", [] (int a, int b) {   return add(a, b);} });
上一篇:Chapter 3 (General Random Variables): Conditioning (条件)
下一篇:微积分:连续性和可导性

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月15日 07时50分21秒