这两个内容没有什么联系, 只是放到一起做一下笔记.
1. lambda函数
python中有lambda函数的用法:
list(map(lambda x: x**2, [1, 2, 3, 4]))
输出:
1, 4, 9, 16
lambda函数是对于表达式不太长的较简单的功能, 尽量缩短代码提高可读性的一种手段. 实际上C++里面也有. 如果从例子入手的话, 比如说, 我要对一个类进行自定义排序. 定义如下的牛马类, 对于一个数组的牛马, 将收入从小到大排. 对于收入相同的, 将年龄从大到小排:
class CowHorse{
private:
std::string m_name;
int m_age;
double m_salary;
public:
CowHorse(const std::string& name, const int age, const double salary) : m_name(std::move(name)), m_age(age), m_salary(salary) {}
bool operator<(CowHorse& ch);
friend std::ostream& operator<<(std::ostream& os, CowHorse& ch);
};
方法一. 重载<运算符
因为sort函数默认是通过从小到大排序(std::less), 所以我们重载<运算符:
bool CowHorse::operator<(CowHorse& ch){
if (this->m_salary != ch.m_salary)
return this->m_salary < ch.m_salary;
else
return this->m_age > ch.m_age;
}
运行
void func(){
std::vector<CowHorse> arr;
arr.push_back(CowHorse("amy", 35, 3000));
arr.push_back(CowHorse("bob", 85, 3000));
arr.push_back(CowHorse("damengzi", 45, 9000));
arr.push_back(CowHorse("fool", 25, 1000));
sort(arr.begin(), arr.end());
for (auto& item: arr){
std::cout << item;
}
}
输出结果:
fool 25 1000
bob 85 3000
amy 35 3000
damengzi 45 9000
方法二. 仿函数
仿函数, 可以理解为函数对象, 即它可以是一个struct或class, 但用的时候当作函数来用, 为此需要重载()运算符. 定义自定义排序的类如下:
struct myCmp_{
bool operator()(CowHorse& ch0, CowHorse& ch1){
return ch0 < ch1;
}
};
调用sort时, 第三个参数传入实例化的myCmp_类:
sort(arr.begin(), arr.end(), myCmp_());
结果也是正确的.
方法三. 函数指针
当然, 更简洁的方式是直接定义函数(因为这个例子比较简单):
bool myCmpFunc(CowHorse& ch0, CowHorse& ch1){
return ch0 < ch1;
}
在调用sort时传入函数指针:
sort(arr.begin(), arr.end(), myCmpFunc);
方法四. lambda函数
lambda函数的格式为:
[返回值](参数){函数体}
或者
[](参数)->返回值类型{函数体}
因此可以这样写:
sort(arr.begin(), arr.end(), [&](CowHorse& ch0, CowHorse& ch1){return ch0 < ch1; });
其中[&]
在这里用不用这个都可以.
补充: 中括号里的[&]
或[=]
的意思是, 按引用或按值的方式捕获表达式前的所有可捕获的变量. 这是什么意思呢? 比如LeetCode的第1030题:
假如我们用最朴素的直接排序法做的话, 我们需要自己定义排序函数. 在这里, 排序的依据不仅仅是每个点的坐标值, 还与其他变量也就是中心点坐标有关, 所以我们用lambda函数是最方便的. 因此我们排序的时候, 还需要捕获rCenter
与cCenter
变量, 就需要用[&]
或[=]
.这里是int, 所以按值传递就可以了.
class Solution {
public:
vector<vector<int>> allCellsDistOrder(int rows, int cols, int rCenter, int cCenter) {
vector<vector<int>> ret;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
ret.push_back({i, j});
}
}
sort(ret.begin(), ret.end(), [=](vector<int>& a, vector<int>& b) {
return abs(a[0] - rCenter) + abs(a[1] - cCenter) < abs(b[0] - rCenter) + abs(b[1] - cCenter);
});
return ret;
}
};
2. 可变参数模板
我们知道, python中有*args与**kwargs用于定义函数的可变参数.
>>> def test(**kwargs):
... if 'name' in kwargs:
... print(kwargs['name'])
...
>>> test(name='asds')
因此, 我们在不确定函数输入参数的时候, 可以这样来用, 并且加条件判断即可. 这样有助于泛化性.
C++中也有这项功能, 只不过不如python这么强大(C++中的可变参数不是哈希表, 不能向上面那样索引)
例如, 我们要定义一个函数, 打印它所有的参数值:
void func() {return;}
template<typename T, typename... Args> // Args是模板参数包, ...放前面
void func(T t, Args... args){ // 函数参数包作为函数参数
std::cout << t; // 打印第一项
func(args...); // 递归调用. 函数参数包后面跟省略号. 注意, 当args为空时, 由于func()未定义, 因此要重载一个func的版本.
}
int main(){
std::string name = "ajsdqwq";
func(name, name, name, name);
system("pause");
return 0;
}
输出:
ajsdqwqajsdqwqajsdqwqajsdqwq
其中, 模板参数包Args是一个类型的列表, 而函数参数包args是一个值的列表, 二者是一一对应的.