本文已参与「新人创作礼」活动,一起开启掘金创作之路。
本文承接上回所说的C++的仿函数
函数对象
C++中的函数对象,是一个非常有用的东西
在STL中,也有许多用到函数对象的地方
比如 sort(begin, end, cmp) 在执行比较操作的时候,sort 会调用cmp来比较两个对象的关系
sort调用的是二元谓词,对应者的函数应该要有两个传参
谓词可以接受的形式:
bool cmp(int a, int b) {
return a > b;
}
struct cmp {
bool operator()(int a, int b) { return a > b;}
}
auto cmp = [](int a, int b) -> bool {
return a > b;
}
lambda 和 函数对象
上回介绍了lambda用类似于宏的方式来进行书写
在c++中应该还是避免用宏的
那么lambda又是仿函数,和模板又可以迸发出什么样子的火花呢?
先看一段例子
int main() {
place _1, _2;
std::vector<int> ve{1, 2, 3, 4, 5};
std::for_each(ve.begin(), ve.end(), std::cout << _1);
}
欸,这段例子中用到了一个for_each, 第三个参数应该要是一个函数对象
可是我们却是一个表达式,这个可以过编译吗?
答案是可以的。
用到的知识点也很简单
那就是 表达式的值
我们知道,在C++中,一个表达式是有值的。
比如:
int a = (2 - 3);
2 - 3 是一个表达式 用 2 - 3 的值来初始化 变量 a
这个有什么用呢?
我们的表达式是不是需要运算符来进行运算所得到操作
运算符可以分为一元、二元和三元运算符
重载运算符 !
template <typename T> struct func {
void operator()(T x) { std::cout << "x" << x << "\n"; }
};
struct tmp {};
template <typename T> func<T> operator+(tmp t, T value) { return func<T>(); }
int main() {
tmp a, b, c;
auto t = a + 1;
t(1);
}
上述代码可以清楚的看成,tmp是一个包裹类,负责把一个式子的运算结果包裹一下,然后返回一个函数对象
至此,我们就可以实现一些操作了
比如:
template <typename T> struct func {
void operator()(T x) { std::cout << "x" << x << "\n"; }
};
struct tmp {};
func<int> operator<<(std::ostream &os, tmp tm) { return func<int>(); }
int main() {
tmp a, b, c;
auto t = std::cout << a;
t(1);
}
就可以实现前面所展示的第三个参数是
std::cout << _1这样的操作
更完整点的例子
我们再来丰富一下自己的这个 类,然后和STL配合起来使用
#include <bits/stdc++.h>
template <typename T> struct eval {
std::ostream &os;
T &_1;
enum TYPE { COUT, ADD, SUB, GREATER, LESS, COMPARE };
TYPE type;
eval(std::ostream &os, T _1, TYPE type) : os(os), _1(_1), type(type) {}
template <typename P> bool operator()(P &t) {
switch (type) {
case COUT:
os << t << " ";
break;
case ADD:
t += _1;
break;
case COMPARE:
return _1 == t;
case SUB:
t -= _1;
}
return true;
}
template <typename A, typename B> bool operator()(const A &a, const B &b) {
switch (type) {
case GREATER:
return a > b;
case LESS:
return a < b;
case COMPARE:
return a == b;
}
}
};
struct place {};
template <typename T> eval<T> operator+=(place p, T val) {
return eval<T>(std::cout, val, eval<T>::ADD);
}
template <typename T> eval<T> operator-=(place p, T val) {
return eval<T>(std::cout, val, eval<T>::SUB);
}
template <typename T> eval<T> operator>(place p, T val) {
return eval<T>(std::cout, val, eval<T>::GREATER);
}
template <typename T> eval<T> operator<(place p, T val) {
return eval<T>(std::cout, val, eval<T>::LESS);
}
template <typename T> eval<T> operator==(place p, T val) {
return eval<T>(std::cout, val, eval<T>::COMPARE);
}
eval<int> operator<<(std::ostream &os, place place) {
return eval<int>(os, 0, eval<int>::COUT);
}
int main() {
place _1, _2;
std::vector<int> ve{1, 2, 3, 4, 5};
std::for_each(ve.begin(), ve.end(), _1 += 2);
std::for_each(ve.begin(), ve.end(), std::cout << _1);
std::cout << " \n";
std::sort(ve.begin(), ve.end(), _1 > _2);
std::for_each(ve.begin(), ve.end(), std::cout << _1);
std::cout << " \n";
std::sort(ve.begin(), ve.end(), _1 < _2);
std::for_each(ve.begin(), ve.end(), std::cout << _1);
std::cout << " \n";
std::for_each(ve.begin(), ve.end(), _1 -= 2);
std::for_each(ve.begin(), ve.end(), std::cout << _1);
std::cout << " \n";
std::cout << std::count_if(ve.begin(), ve.end(), _1 == 2);
return 0;
}
上述代码虽然写得很丑,但是基本功能还是实现了的
那么,上面的表达式都很简单啊,都没有复杂一点的
学过编译原理都应该知道
复杂表达式也是可以由简单表达式所构成的
比如
"*"
/ \
"1 + 2" "( 3 - 4 )"
那么,我们是不是能够利用模板编程来实现这样的东西呢 ?