函数对象 谓词
//算法中的函数对象和谓词
//for_each find_if transform sort
#include <iostream>
#include <algorithm>
//#include <functional>
#include <vector>
#include <string>
#include <set>
using namespace std;
template <typename T> //定义类模板
class ShowElemt
{
public:
ShowElemt()
{
n = 0;
}
void operator()(T &t) //定义函数对象
{
n++; //保持调用状态信息
cout << t << " ";
printN();
}
void printN()
{
cout << "n: " << n << endl;
}
private:
int n;
};
template <typename T> //定义函数模板
void showElemt(T &t)
{
cout << t << endl;
}
void showElemt2(int &t) //定义普通函数
{
cout << t << " ";
}
//函数对象的定义 函数对象和普通函数的异同
void test01()
{
int a = 10;
ShowElemt<int> s1;
s1(a); //函数对象的调用和普通函数很相似
showElemt<int>(a);
showElemt2(a);
}
//函数对象属于类对象,能保持调用状态信息
//函数对象的好处
//for_each算法中,函数对象做函数参数
//for_each算法中,函数对象做返回值
void test02()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
//遍历的作用
for_each(v1.begin(), v1.end(), ShowElemt<int>()); //匿名函数对象 匿名仿函数
for_each(v1.begin(), v1.end(), showElemt2); //通过回调函数 谁使用for_each 谁去填写回回调函数入口地址
ShowElemt<int> s1;
//函数对象做函数参数
for_each(v1.begin(), v1.end(), s1);
s1.printN(); //此时 n=0 ==>函数对象的传递 是 实参值赋给形参 是元素值传递 不是引用
cout << "通过for_each算法的返回值看调用次数:" << endl;
s1= for_each(v1.begin(), v1.end(), s1); //返回函数对象
s1.printN();
}
//结论 要点:分清楚STL算法返回的值是 迭代器 还是 谓词(函数对象) 是STL算法入门的重要点
//一元谓词案例
template <typename T>
class IsDiv
{
public:
IsDiv(const T &divisor)
{
this->divisor = divisor;
}
bool operator()(T &t)
{
return (t%divisor == 0);
}
private:
T divisor;
};
void test03()
{
vector<int> v2;
for (int i = 20; i < 33; i++)
{
v2.push_back(i);
}
vector<int>::iterator it;
it = find_if(v2.begin(), v2.end(), IsDiv<int>(4)); //一元谓词做函数参数
if (it == v2.end())
{
cout << "v2 中没有被4整除的值" << endl;
}
else
{
cout << "第一个被4整除的值是:" << *it << endl;
}
}
//二元函数对象案例
template <typename T>
class SunAdd
{
public:
T operator()(T t1, T t2) //二元函数对象
{
return t1 + t2;
}
};
void test04()
{
//v1 v2 ==> v3
vector<int> v1, v2;
vector<int> v3;
v1.push_back(1);
v1.push_back(3);
v1.push_back(5);
v2.push_back(2);
v2.push_back(4);
v2.push_back(6);
v3.resize(10);
//二元函数对象做函数参数
transform(v1.begin(), v1.end(), v2.begin(), v3.begin(), SunAdd<int>());
for (vector<int>::iterator it = v3.begin(); it != v3.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//二元谓词案例
template <typename T>
bool myCompare(const T &a, const T &b)
{
return a > b; //降序排列
}
void test05()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
int tmp = rand() % 100;
v1.push_back(tmp);
}
for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
{
cout << *it << " ";
}
cout << endl;
//也可以用for_each来遍历
for_each(v1.begin(), v1.end(), showElemt2);
cout << endl;
sort(v1.begin(), v1.end(), myCompare<int>); //二元谓词做函数参数
for_each(v1.begin(), v1.end(), showElemt2);
cout << endl;
}
//二元谓词在set集合中的应用
struct CompareNoCase
{
bool operator()(string &str1, string &str2)
{
//将两个字符串都变为大写或小写进行比较,则不需要区分大小写
string str1_;
str1_.resize(str1.size()); //为str1_分配空间
transform(str1.begin(), str1.end(), str1_.begin(), tolower);//都转换为小写 预定义函数对象
string str2_;
str2_.resize(str2.size()); //为str1_分配空间
transform(str2.begin(), str2.end(), str2_.begin(), tolower);//都转换为小写
return str1_ < str2_;
}
};
void test06()
{
set<string> s1;
s1.insert("aaa");
s1.insert("bbb");
s1.insert("ccc");
set<string>::iterator it = s1.find("aAa"); //find函数默认区分大小写
if (it == s1.end())
{
cout << "没有找到 aaa" << endl;
}
else
{
cout << "找到 aaa" << endl;
}
//使用二元谓词使find不区分大小写
set<string, CompareNoCase> s2;
s2.insert("aaa");
s2.insert("bbb");
s2.insert("ccc");
set<string, CompareNoCase>::iterator it2 = s2.find("aAa");
if (it2 == s2.end())
{
cout << "没有找到 aaa" << endl;
}
else
{
cout << "不区分大小写 找到 aaa" << endl;
}
}
int main()
{
//test01();
//test02();
//test03();
//test04();
//test05();
test06();
system("pause");
return 0;
}
测试 test06 后
出现问题:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2664 “bool CompareNoCase::operator ()(std::string &,std::string &)”: 无法将参数 1 从“const std::basic_string<char,std::char_traits<char>,std::allocator<char>>”转换为“std::string &” Test014 d:\vs2017\visual studio ide\vc\tools\msvc\14.16.27023\include\xtree 1426
然后先前可以正常运行的 test01-test05 都出现这个错误了......
why???
问题解决:
set<string, CompareNoCase> 具有const属性,但是调用该set<string, CompareNoCase>的表达式(也就是bool operator()(const string &str1, const string &str2)不具有const属性,丢失const,所以无法通过编译。
调用operator()的时候要求operator()也具有const属性,否则就会导致丢失const限定符的错误。
因此解决办法就是给operator()加上const属性。
如下:
struct CompareNoCase
{
//要给函数加上const解决只读属性的问题
//bool operator()(const string &str1, const string &str2)
bool operator()(const string &str1, const string &str2) const
{
//将两个字符串都变为大写或小写进行比较,则不需要区分大小写
string str1_;
str1_.resize(str1.size()); //为str1_分配空间
transform(str1.begin(), str1.end(), str1_.begin(), tolower);//都转换为小写 预定义函数对象
string str2_;
str2_.resize(str2.size()); //为str1_分配空间
transform(str2.begin(), str2.end(), str2_.begin(), tolower);//都转换为小写
return (str1_ < str2_);
}
};