(1)STL算法之遍历容器
1、for_each() 遍历容器
在实现遍历的基础上,利用参数三(仿函数)实现其他操作,仅遍历打印,或者遍历更改容器值。
【原型】
template <class InputIterator, class Function>
Function for_each (InputIterator first, InputIterator last, Function fn);
参数一:迭代器
参数二:迭代器
参数三:仿函数(也可以叫 函数对象)
#include <iostream>
#include <algorithm> // std::for_each
#include <vector>
void myfunction(int i) { // function: 仅遍历打印容器内的值
std::cout << ' ' << i;
}
struct myclass { // function object type:
void operator() (int i) //仅遍历打印容器内的值
{
std::cout << ' ' << i;
}
} myobject;
int main()
{
std::vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(30);
std::cout << "myvector contains:";
for_each(myvector.begin(), myvector.end(), myfunction);
std::cout << '\n';
// or
std::cout << "myvector contains:";
for_each(myvector.begin(), myvector.end(), myobject);
std::cout << '\n';
return 0;
}
对于参数3 函数如何调用的问题,我疑惑了很久,今天百度了很长时间,然后想起来看源码,忽然就有点明白了。
for_each()源码
// FUNCTION TEMPLATE for_each
template <class _InIt, class _Fn>
_Fn for_each(_InIt _First, _InIt _Last, _Fn _Func) // perform function for each element [_First, _Last)
{
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First); // 获取 first 迭代器指向的地址
const auto _ULast = _Get_unwrapped(_Last); // 获取 Last 迭代器指向的地址
for (; _UFirst != _ULast; ++_UFirst) // 放入一个for 循环,遍历容器中所有值的地址
{
_Func(*_UFirst); // * _UFirst 拿出此地址的值,作为参数,传递到参数3 中
}
return _Func; //返回函数对象的最终状态
}
以下示例来自用户文章:C++for_each()的返回值,使用for_each的返回值,获取1-100的总和,
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*
for_each()它可以返回其仿函数(返回所传入的函数对象的最终状态).
这样我们就可以通过for_each()的返回值来获取仿函数的状态.
*/
class CSum
{
public:
CSum(){
m_sum = 0;
}
void operator()(int n)/* 仿函数 */{
m_sum += n;
}
int GetSum() const{
return m_sum;
}
private:
int m_sum;
};
int main()
{
vector<int> vi;
for (int i = 1; i <= 100; i++)
{
vi.push_back(i);
}
//通过for_each返回值访问其最终状态(返回所传入的函数对象的最终状态).
CSum cs = for_each(vi.begin(), vi.end(), CSum());//最后一个参数相当于用CSum创建了一个无参对象
cout << cs.GetSum() << endl;
return 0;
}
在for_each()的基础之上,通过仿函数类,使容器内的元素 * 2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template <class T>
void FillValue(T& vect, int first, int last){ // 初始化容器
if (last >= first){
for (int i = first; i <= last; ++i)
vect.insert(vect.end(), i);
}
}
void print(int elem){ // 函数对象
cout << elem << " ";
}
template <class T>
class Multiple { // 仿函数类,
private:
T theValue;
public:
Multiple(const T& v) : theValue(v)
{
}
void operator()(T& elem) const // 重载 (),使类具有类似函数的行为,就是仿函数类
{
elem *= theValue; // * theValue
}
};
void main()
{
vector <int> myvector;
FillValue(myvector, 1, 10); // 给容器赋值 1-10
for_each(myvector.begin(), myvector.end(), print); // 仅遍历 打印
cout << endl;
for_each(myvector.begin(), myvector.end(), Multiple<int>(2)); //遍历 更改 容器值
for_each(myvector.begin(), myvector.end(), print);
cout << endl;
}
对以上示例中的class Multiple 仿函数类(该名词出现在《C++STL标准程序库设计指南》),作者的解释是:在类中实现函数operator(),之后这个类就有了类似函数的行为,就是一个仿函数类。
仿函数:《C++标准程序库》的解释是:仿函数是泛型编程强大威力和纯粹抽象概念的又一例证。可以说,任何东西,只有其行为像函数,他就是一个函数,因此如果你定义了一个对象,行为像函数,它就可以当做函数来使用。
那么什么才算具备函数行为呢?所谓函数行为,是指可以使用圆括号传递参数,借以调用某个东西。重载()即可。