写在前面
今天在看《STL源码剖析》的时候,看到了配接器中的ostream iterator,其中包含istream_iterator以及ostream_iterator以及更多,感觉这两个都十分重要,所以在这里介绍一下
istream_iterator
源码:
template <class T, class Distance = ptrdiff_t>
class istream_iterator {
friend bool
operator== __STL_NULL_TMPL_ARGS (const istream_iterator<T, Distance>& x,
const istream_iterator<T, Distance>& y);
protected:
istream* stream;
T value;
bool end_marker; //判断是否读入结束符,比如C语言中的EOF等等
void read() { //其中调用的读取函数
end_marker = (*stream) ? true : false;
if (end_marker) *stream >> value; //读入value
end_marker = (*stream) ? true : false;
}
public:
typedef input_iterator_tag iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef const T* pointer;
typedef const T& reference;
istream_iterator() : stream(&cin), end_marker(false) {} //默认构造函数,不会触发输入操作
istream_iterator(istream& s) : stream(&s) { read(); } //这种构造函数,后面就紧跟着读取一个数据
reference operator*() const { return value; }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
istream_iterator<T, Distance>& operator++() { //重点重载operator++
read();
return *this;
}
istream_iterator<T, Distance> operator++(int) { //将operator++重载为输入操作
istream_iterator<T, Distance> tmp = *this;
read();
return tmp;
}
};
构造方法:
istream_iterator<int> intie(cin); //后面紧跟要输入一个数据
istream_iterator<int> intie_(); //默认构造方法
通过上面的源码知道,当调用istream_iterator对象的operator++操作时,就会被重载为输入一个对象
ostream_iterator
源码:
template <class T>
class ostream_iterator {
protected:
ostream* stream;
const char* string; //可以包含第二个参数,输出对应的数据后,输出此stream
public:
typedef output_iterator_tag iterator_category; //迭代器类型
typedef void value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
ostream_iterator(ostream& s) : stream(&s), string(0) {} //缺省一个参数的构造函数,默认string为空
ostream_iterator(ostream& s, const char* c) : stream(&s), string(c) {} //包含string的构造函数
ostream_iterator<T>& operator=(const T& value) { //重点!!!重载operator=操作,转换为输出此value
*stream << value;
if (string) *stream << string;
return *this;
}
ostream_iterator<T>& operator*() { return *this; } //都返回本身
ostream_iterator<T>& operator++() { return *this; }
ostream_iterator<T>& operator++(int) { return *this; }
};
构造方式:
ostream_iterator<int> outie(cout); //string默认为null
ostream_iterator<int> outie_(cout, " !! "); //同时也构造string
通过源码看出,当ostream_iterator遇到operator=操作是,会被重载为输出操作。
具体用法
使用ostream_iterator以及istream_iterator的时候,要确保使用对应的方法,例:
#include <iostream>
#include <thread>
#include <vector>
#include <numeric>
#include <algorithm>
#include <cstring>
#include <deque>
#include <iterator>
using namespace std;
int main()
{
deque<int> id;
istream_iterator<int> intie(cin),eos; //开始触发一次输入
copy(intie, eos, inserter(id, id.begin())); //迭代器类型为InputIterator,所以这里调用copy的时候采用*result = *first;版本,会使用重载类型 ,那么就会转换为插入操作
//其中++first会继续调用下一个,然后重载为新的输入
ostream_iterator<int> outie(cout, " "); //deque的迭代器类型为random_access_iterator,也会是 *result = *first;调用赋值操作 result++操作,返回本身,不影响后面的输出操作
copy(id.begin(), id.end(), outie); //将=操作,转换为输出操作
cout << endl;
system("pause");
}
我们这里使用的第一个copy方法,里面采用循环赋值的方式进行操作,如下:
template <class InputIterator, class OutputIterator>
inline OutputIterator __copy(InputIterator first, InputIterator last, //迭代器类型为input_iterator
OutputIterator result, input_iterator_tag)
{
for ( ; first != last; ++result, ++first) //直接以迭代器是否相等来进行判断循环是否继续进行,速度慢
*result = *first;
return result;
}
第二个copy方法,也是采用循环赋值的方式操作(因为deque中迭代器的类型为:random_access_iterator_tag):
template <class RandomAccessIterator, class OutputIterator, class Distance>
inline OutputIterator
__copy_d(RandomAccessIterator first, RandomAccessIterator last, //双向可执行,以n为执行次数,速度快
OutputIterator result, Distance*)
{
for (Distance n = last - first; n > 0; --n, ++result, ++first)
*result = *first;
return result;
}
所以可以直接调用ostream_iterator的对象,进行文本输出
同时copy函数中的++first操作,也会调用istream_iterator对象的++操作,对文本进行输入,在第一个copy函数中的inserter参数为iterator adpapters,可以将赋值操作转换为插入操作,将输入内容插入到deque中。
参考书籍
《STL源码剖析》侯捷著