泛型算法的定制操作多种实现方式
sort 要求第三个参数为 二元谓词
//比较函数
bool isShorter(const string &s1, const string &s2)
{
return s1.size() < s2.size();
}
//测试vector
vector<string> strVec = {"cc","abc","hjg","das","dfgsdsd","abc","aa","cc","b","a","hjg" };
//用<进行比较 结果参照string使用<进行比较的结果
sort(strVec.begin(), strVec.end());
//传入比较函数作为谓词 因为sort接受二元谓词,所以比较函数也得是两个参
//将vec按照从短到长排序
sort(strVec.begin(), strVec.end(), isShorter);
//使用lamda表达式
//同上
sort(strVec.begin(), strVec.end(), [](const string &s1, const string &s2) {return s1.size() < s2.size(); });
find_if 要求第三个参数为一元谓词
//一个形参 可以作为一元谓词传给find_if
bool islonger1(const string &s1)
{
return s1.size() > 2;
}
//两个形参 不可以传给find_if
bool islonger2(const string &s1,size_t sz)
{
return s1.size() > sz;
}
//测试数据依然使用上面sort的内容
size_t sz = 2;
//不用在意重定义,只是突出介绍方式
//如果你想找到第一个长度为3的string,可以继续使用这种方式
//但3已经被硬编码进函数,需求改变就只能再写不同的判断函数
auto wc = find_if(strVec.begin(), ve.end(), islonger1);
//这个时候 咱们的lambda表达式就排上用场的
//捕获列表我自己捕获一个,实际参数还是只有1个
//mutable->bool 这个可以忽略,写在这里是因为后面要介绍lambda原理
auto wc = find_if(strVec.begin(), strVec.end(), [sz](const string &s1)mutable->bool {return s1.size() > sz; });
//参数绑定 std::bind
//可以理解为它为islonger2套了层壳
//感兴趣的可以自己查阅一下资料
auto wc = find_if(strVec.begin(), ve.end(), bind(islonger2, std::placeholders::_1,sz));
//--------------------------
class A
{
public:
A(size_t a) :pa(a) {}
bool operator ()(string x)
{
return x.size() > pa;
}
private:
const size_t pa;
};
//这种方法就比较秀了 如果对于这种操作比较困惑,咱们得去看find_if的源码
auto wc = find_if(strVec.begin(), strVec.end(),A(sz));
find_if源码
// FUNCTION TEMPLATE find_if
template<class _InIt,
class _Pr>
_NODISCARD inline _InIt find_if(_InIt _First, const _InIt _Last, _Pr _Pred)
{ // find first satisfying _Pred
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
for (; _UFirst != _ULast; ++_UFirst)
{
//看到没有 上面最后一种方式 创建的临时对象调用被你重载的()运算符
//刚好得到了find_if的条件判断
//也解释了为什么find_if只能接受一个参数的比较函数
//这里如果传入islonger1 就变成了 islonger1(*_UFirst)
if (_Pred(*_UFirst))
{
break;
}
}
_Seek_wrapped(_First, _UFirst);
return (_First);
}
总结:
三种方式来使原本只能接受一元谓词的函数处理多个入参
- lambda表达式
- std:bind
- 定义一个类,重载其()运算符,类成员在构造的时候变为额外入参
而且从源码上面可以得知,第二种和正常传入比较函数是同一种方式(普通函数调用),而第三种方式则是使用类重载运算符实现(也是调用函数,但使用的是类成员函数).
那么lambda是怎么办到的呢? mutable这个关键词是不是有种似曾相识,感觉在哪里见过?
后面有机会再写