
🎬 个人主页 :艾莉丝努力练剑
❄专栏传送门 :《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》
《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》
⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平
🎬 艾莉丝的简介:

🎬 艾莉丝的C++专栏简介:

文章目录
- C++学习阶段的三个参考文档
- [8 ~> 包装器](#8 ~> 包装器)
-
- [8.1 function](#8.1 function)
-
- [8.1.1 结构](#8.1.1 结构)
- [8.1.2 概念](#8.1.2 概念)
- [8.1.3 function实现](#8.1.3 function实现)
- [8.1.4 重写逆波兰表达式求值](#8.1.4 重写逆波兰表达式求值)
- [8.2 bind](#8.2 bind)
-
- [8.2.1 结构](#8.2.1 结构)
- [8.2.2 概念](#8.2.2 概念)
- [8.2.3 代码实现](#8.2.3 代码实现)
- [9 ~> 智能指针预告](#9 ~> 智能指针预告)
- C++11完整代码示例与实践演示
- 结尾
C++学习阶段的三个参考文档
看库文件(非官方文档): Cplusplus.com

这个文档在C++98、C++11时候还行,之后就完全没法用了......
准官方文档(同步更新) ------还 可以看语法 :C++准官方参考文档

这个行,包括C++26都同步了,我们以后主要会看这个。
官方文档(类似论坛): Standard C++

这个网站上面会有很多大佬,类似于论坛。

8 ~> 包装器
8.1 function
8.1.1 结构
cpp
template <class T>
class function; // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
8.1.2 概念
std::function 是一个类模板,也是一个包装器 std::function 的实例对象可以包装存储其他的可以调用对象,包括函数指针、仿函数、lambda 、 bind表达式 等,存储的可调用对象被称为 std::function 的目标。若std::function不含目标,则称它为空。调用空 std::function 的目标导致抛出std::bad_function_call异常。

以上是function的原型,他被定义头文件中。std::function是function的官方文件链接。

函数指针、仿函数、 lambda 等可调用对象的类型各不相同, std::function 的优势就是统一类型,对他们都可以进行包装,这样在很多地方就方便声明可调用对象的类型,下面的第二个代码样例展示了 std::function 作为map的参数,实现字符串和可调用对象的映射表功能。
8.1.3 function实现


8.1.4 重写逆波兰表达式求值
力扣题目链接: 150. 逆波兰表达式求值
力扣题解链接: 后缀法 && 操作符紧跟操作数 && switch...case...语句解决
这道题我们已经写过一次了,这次我们会采用另一种方式实现。
题目描述:

对应博客链接: 【C++STL :stack && queue (一) 】STL:stack与queue全解析|深入使用(附高频算法题详解)

传统方式实现(之前的实现)------
cpp
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for(auto& str : tokens)
{
// 判断四种运算符
if(str == "+" || str == "-" || str == "*" || str == "/")
{
// 运算符
int right = st.top();
st.pop();
int left = st.top();
st.pop();
switch(str[0]) // 大坑:switch...case语句只能是int类型
{
case '+':
st.push(left + right);
break;
case '-':
st.push(left - right);
break;
case '*':
st.push(left * right);
break;
case '/':
st.push(left / right);
break;
}
}
else
{
// 运算数
st.push(stoi(str)); // 字符串转整型,to_string
}
}
return st.top();
}
};
我们可以现学现用,使用map映射string和function的方式实现一下------

这种方式的最大优势之一是方便扩展,假设还有其他运算,我们增加map中的映射即可,算法实现如下所示------
cpp
class Solution{
public:
int evalRPN(vector<string>& tokens) {
map<string,function<int(int,int)>> opFuncMap =
{
{"+",[](int a,int b) {return a + b;}},
{"-",[](int a,int b) {return a - b;}},
{"*",[](int a,int b) {return a * b;}},
{"/",[](int a,int b) {return a / b;}}
};
stack<int> st;
for(auto& str : tokens)
{
if(opFuncMap.count(str))
{
// 运算符
int right = st.top();
st.pop();
int left = st.top();
st.pop();
int ret = opFuncMap[str](left,right);
st.push(ret);
}
else{
// 运算数
st.push(stoi(str));
}
}
return st.top();
}
};
8.2 bind
8.2.1 结构
cpp
simple(1)
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
with return type (2)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
8.2.2 概念
bind 是一个函数模板,它也是一个可调用对象的包装器,可以把他看做一个函数适配器,对接收的fn可调用对象进行处理后返回一个可调用对象。 bind 可以用来调整参数个数和参数顺序。 bind 也在这个头文件中。
调用bind的一般形式:
cpp
auto newCallable =bind(callable,arg_list);
其中newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。
arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是占位符,表示newCallable的参数,它们占据了传递给newCallable的参数的位置。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。_1 / _2 / _3...这些占位符放到placeholders的一个命名空间中。

8.2.3 代码实现

9 ~> 智能指针预告
C++专栏的主线内容马上就要结束啦,艾莉丝将把智能指针作为C++干货专栏的主线(C++98、C++11部分)的终章,之后本专栏还会更新,内容以C++11、C++14、C++17、C++20、以及其它的加餐内容为主了。感谢大家对艾莉丝的支持!希望uu们能够继续支持艾莉丝哦!感谢大佬们的支持!
C++11完整代码示例与实践演示
Test.cpp:
cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<functional>
using namespace std;
// ===================C++11:包装器=================
//--------------------function---------------------
int f(int a, int b)
{
return a + b;
}
struct Functor
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
class Plus
{
public:
Plus(int n = 10)
:_n(n)
{}
static int plusi(int a, int b)
{
return a + b;
}
double plusd(double a, double b)
{
return (a + b) * _n;
}
private:
int _n;
};
//int main()
//{
// // 类型擦除
// function<int(int, int)> f1 = f;
// function<int(int, int)> f2 = Functor();
// function<int(int, int)> f3 = [](int a, int b) {return a + b; };
// cout << f1(1, 1) << endl;
// cout << f2(1, 1) << endl;
// cout << f3(1, 1) << endl;
//
// vector<function<int(int, int)>> v;
// v.push_back(f);
// v.push_back(Functor());
// v.push_back([](int a, int b) {return a + b; });
//
// for (auto& f : v)
// {
// cout << f(1, 1) << endl;
// }
// cout << endl;
//
// //function<int(int, int)> f4 = Plus::plusi;
// function<int(int, int)> f4 = &Plus::plusi;
// cout << f4(1, 1) << endl;
//
// function<double(Plus*, double, double)> f5 = &Plus::plusd;
// Plus ps;
// cout << f5(&ps, 1.1, 1.1) << endl;
//
// function<double(Plus, double, double)> f6 = &Plus::plusd;
// cout << f6(ps, 1.1, 1.1) << endl;
//
// function<double(Plus, double, double)> f7 = &Plus::plusd;
// cout << f7(Plus(), 1.1, 1.1) << endl; // Plus():匿名对象
//
// function<double(Plus&&, double, double)> f8 = &Plus::plusd;
// cout << f8(Plus(), 1.1, 1.1) << endl;
//
// auto pf1 = &Plus::plusd;
// Plus* ptr = &ps;
// cout << (ps.*pf1)(1.1, 1.1) << endl;
// cout << (ptr->*pf1)(1.1, 1.1) << endl; // 无法显式传this指针
//
// return 0;
//}
// 运行结果:
// 2
// 2
// 2
// 2
// 2
// 2
//
// 2
// 22
// 22
// 22
// 22
// 22
// 22
// ------------------bind-------------------
// _n占位
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int a, int b)
{
return (a - b) * 10;
}
int SubX(int a, int b, int c)
{
return(a - b - c) * 10;
}
int main()
{
// bind的本质是返回一个仿函数对象
// 调整参数顺序(这个功能不常用)
// _1代表第一个实参
// _2代表第二个实参
// ...
// 交换
auto f1 = bind(Sub, _1, _2);
auto f2 = bind(Sub, _2, _1);
// _1代表第一个实参
// _2代表第二个实参
cout << f1(10, 5) << endl;
cout << f2(10, 5) << endl;
// 调整参数个数
auto f3 = bind(SubX, 10, _1, _2);
cout << f3(15, 5) << endl;
// _1代表第一个实参
// _2代表第二个实参
// 底层operator(),调用SubX,第一个参数10, 15, 5
auto f4 = bind(SubX, _1, 10, _2);
cout << f4(15, 5) << endl;
// 底层operator(),调用SubX,第一个参数15, 10, 5
auto f5 = bind(SubX, _1, _2, 10);
cout << f5(15, 5) << endl;
// 底层operator(),调用SubX,第一个参数15, 5, 10
function<double(Plus, double, double)> f7 = &Plus::plusd;
cout << f7(Plus(), 1.1, 1.1) << endl;
cout << f7(Plus(), 2.2, 1.1) << endl;
cout << f7(Plus(), 3.3, 1.1) << endl;
function<double(Plus&&, double, double)> f8 = &Plus::plusd;
cout << f8(Plus(), 1.1, 1.1) << endl;
cout << f8(Plus(), 2.2, 1.1) << endl;
cout << f8(Plus(), 3.3, 1.1) << endl << endl;
// 计算复利(利息)的lambda
auto func1 = [](double rate, double money, int year)->double {
double ret = money;
for (int i = 0; i < year; i++)
{
ret += ret * rate;
}
return ret - money;
};
// 年利率1.5%
function<double(double)> func_r1_5_3y = bind(func1, 0.015, _1, 3);
function<double(double)> func_r1_5_5y = bind(func1, 0.015, _1, 5);
function<double(double)> func_r1_5_20y = bind(func1, 0.015, _1, 20);
// 本金100000元
cout << func_r1_5_3y(100000) << endl;
cout << func_r1_5_5y(100000) << endl;
cout << func_r1_5_20y(100000) << endl;
// 这只股票如果利率有10%呢
function<double(double)> func_r10_3y = bind(func1, 0.1, _1, 3);
function<double(double)> func_r10_5y = bind(func1, 0.1, _1, 5);
function<double(double)> func_r10_20y = bind(func1, 0.1, _1, 20);
cout << func_r10_3y(100000) << endl;
cout << func_r10_5y(100000) << endl;
cout << func_r10_20y(100000) << endl;
// 如果你的10万元到了"股神"巴菲特手里------19%,同样的时间会怎么样?
function<double(double)> func_r19_3y = bind(func1, 0.19, _1, 3);
function<double(double)> func_r19_5y = bind(func1, 0.19, _1, 5);
function<double(double)> func_r19_20y = bind(func1, 0.19, _1, 20);
cout << func_r19_3y(100000) << endl;
cout << func_r19_5y(100000) << endl;
cout << func_r19_20y(100000) << endl;
return 0;
}
// 运行结果:
// 50
// -50
// -100
// 0
// 0
// 22
// 33
// 44
// 22
// 33
// 44
//
// 4567.84
// 7728.4
// 34685.5
// 33100
// 61051
// 572750
// 68515.9
// 138635
// 3.14294e+06
结尾
uu们,本文的内容到这里就全部结束了,艾莉丝再次感谢您的阅读!
结语:希望对学习C++相关内容的uu有所帮助,不要忘记给博主"一键四连"哦!
往期回顾:
【C++:C++11】C++11新特性深度解析:从可变参数模板到Lambda表达式
🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡 ૮₍ ˶ ˊ ᴥ ˋ˶₎ა
