C++ STL和泛型编程(三)----适配器(Adapters)

一、作用及类别

Adapter是将某个已经存在的东西改造一下,如改下接口(两个参数的改为一个参数)或改下函数名称之类的。

在编程技术上,A若要取用B的功能并代表B,有两种方式:A继承BA内含B(复合),而adapters选用的都是内含(复合)关系
在这里插入图片描述所以adapters有三种类型:Container Adapters, Iterator Adapters, Functor Adapters
由图知,是Functor Adapters向Functors提问,然后Functors回答给Functor Adapters获得first_argument_type, second_argument_type, result_typeargument_type, result_type,最后Algorithms再通过Functor Adapters来操作实现。

二、Container Adapters

在这里插入图片描述这里的deque<T>即为adapter,因为其是调用部分deque的函数,然后封装在新的函数名称内,如:
push()实际底部为c.push_back(),
pop()实际底部为pop_back()。

三、Functor Adapters

- binder2nd

// functor less
template<class T>
struct less: public binary_function<T, T, bool>{ // 继承了binary_function,则可回答adapter提问的first_argument_type, second_argument_type和result_type
	bool operator()(const T& x, const T& y) const{
		return x < y;
	}
};

template<class Operation>
class bider2nd: public unary_function<typename Operation::first_argument_type, 
									  typename Operator::result_type>{
protected:
	Operation op;
	typename Operation::second_argument_type value; // 为了后续判断传入参数类型是否与要求的类型相符合
public:
	// constructor
	binder2nd(const Operation& x, 
			  const typename Operation::second_argument_type& y): op(x), value(y){}
	typename Operation::result_type  // 询问返回的应该是什么类型
		operator()(const typename Operation::first_argument_type& x) const{
			return op(x, value);
	}
};

// 辅助函数,让user得以方便使用binder2nd<Operation>
// 通过辅助函数编译器自动推导O配ration的type
template<class Operation, class T>
inline binder2nd<Operation> bind2nd(const Operation& op, const T& x){
	typedef typename Operation::second_argument_type arg2_type; // 为了后续判断传入参数类型是否与要求的类型相符合
	return binder2nd<Operation>(op, arg2_type(x)); // 调用的是binder2nd的构造函数
};

template<class InputIterator, class Predicate>
typename iterator_traits<InputIterator>::difference_type
	count_if(InputIterator first, InputIterator last, Predicate pred){
		typename iterator_traits<InputIterator>::difference_type n = 0;
		for(; first != last; ++first)
			if(pred(*first))
				++n;
		return n;	
}

int main(){
	...
	cout << count_if(v1.begin(), v1.end(), not1(bind2nd(less<int>(), 40)));
}

count_if()是求迭代器v1.begin()到v1.end()范围内的元素,小于40的元素的个数,且其第三模板参数类型暗示为Predicate型

先看 辅助函数bind2nd(less<int>(), 40)【其返回值类型是binder2nd<Operation>】,其中的less<int>()此时只是相当于一个函数对象并没有实际进入调用仿函数less<int>的阶段。然后通过辅助函数bind2nd的源码知,其传入第一参数less<int>() 即一个临时函数类对象,并且由编译器推导出第一参数的类型Operation实际上是less<int>型这也是辅助函数的作用之处】,同理传入第二参数为40也会推导出其类型为int型。接着提问并得到 less<int> 所继承的binary_function的第二参数类型second_argument_type,并定义其新别名arg2_type。接着binder2nd<Operation>(op, arg2_type(x))【类名+() 表示创建的是一个临时对象】调用的是binder2nd类构造函数

binder2nd(const Operation& x, const typename Operation::second_argument_type& y): op(x), value(y){}
其中的第一传入参数x为 less<int>() 临时对象,第二传入参数为int型对象40。

另外:
1.arg2_type(x)这里是前置判断,判断 less<T>所继承的binary_function的第二参数类型second_argument_type实际上即是T,是否和第二传入参数x的类型一致,不一致的话直接报错,就不用再进行后续操作了【因为 类型名 +(a)int(a) 表示创建一个临时对象并赋值,如果a的类型与int型不符,则是无法进行临时对象的赋值操作的,即编译报错!】。避免了在一开始不检查类型是否符合,一直执行到实际操作了才开始出错,浪费代码执行时间的情况
2.typename Operation::second_argument_type value的操作也是为了实现上述的判断类型是否符合的要求
3.typename Operation::result_type
operator()(const typename Operation::first_argument_type& x) const{return op(x, value);}
中的typename Operation::result_type实际上提问的是less<int>::result_type是何类型,由上述class less的源码知其是bool类型。

此时经过binder2nd类构造函数后生成的是一个binder2nd类临时对象,并返回。注意,此时依旧是没有调用进入仿函数less<int>内部的比较操作步骤,只是一个less<int>()的临时对象和40被记录在binder2nd类的op变量和value变量中。

最后回到count_if中,其第三参数经过上述步骤传入的是一个binder2nd类对象【仿函数】即第三参数类型Predicate为binder2nd类,第三参数对象pred为实际传入的经过binder2nd构造函数生成的内部成员变量已赋值【 op(less<int>())和value(40)】的对象。此时进入count_if的源代码,在进行到if(pred(*first))时,pred(*first)相当于调用binder2nd的operator()【因为pred可看成binder2nd pred,则pred(*first)相当于调用了operator(const typename Operation::first_argument_type& x)实际上等同于operator(const int& x),而x为传入参数*first】,并且传入*first值,于是便进入operator()的op(x, value)代码段【这里的op为less<int>()即为一个less<int>类的临时对象,value为40】即相当于less<int>()(*first, value),这时才是进入到类less<int>的内部并绑定value进行比较操作,传入不断移动的*first元素逐一与绑定的value进行比较,并返回bool值,若返回值为真则++n,从而最终达到计数的操作。

注意
1.为什么不直接用仿函数binder2nd:
因为binder2nd是一个类模板,使用时其需指定模板参数Operation,而一般情况很难指定如less<int>这种模板参数,所以借用辅助函数bind2nd()来推导出Operation,然后再调用binder2nd并指定已推导出的Operation模板参数。

2.typename的作用:
帮助编译器去通过如 typename Operation:: second_argument_type value的代码,因为编译器在编译此代码段时,因为还没有被使用,不知道Operation具体是什么对象,万一Operation是一个变量,则 变量:: 这样的操作是错误的!而加了typename关键字后,明确告诉编译器这是个类型声明,可以通过!

3.class binder2nd【本身是一个functor】作为一个function adapter在修饰完struct less: public binary_function<T, T, bool>的仿函数后,其考虑到如果binder2nd本身还有需要要被adapter的话,必须也得回答adapter的提问,所以仿函数binder2nd继承了unary_function<T, T>。因而其将Adaptable Binary Function转换为 Unary Function即本身两个接口的转化为一个接口了
(A代表B,如果A此时也想被其他东西代表或改造,则A也应该继承binary_function或unary_function)

- not1

在这里插入图片描述与上述操作类似,这里调用unary_negate的构造函数创建临时对象时,实际上只是将上述生成的binder2nd类临时对象记录下来即赋值给pred。在进入到count_if的调用即实际上进入unary_negta的operator()的内部操作时,!pred(x) 也只是在执行上述相当于less<int>()(*first, value) 的操作的基础上取反而已。

- bind

使用 bind 时必须引入头文件 #include<functional> ,其可以绑定:
1.functions
2.function objects
3.member functions, 若使用_1(占位符) 则必须是某个object地址
4.data members, 若使用_1(占位符) 则必须是某个object地址

返回一个function object ret,调用ret相当于调用上述1,2,3(调用函数),或相当于取出4(取出变量)。而 _x_1 , _2 , _3 等是占位符用以表示相应的对象。

double my_divide(double x, double y){
	return x / y;
}
struct Mypair{
	double a, b;
	double multiply(){ // member function实际有个argument: this
		return a * b;
	}
}

using namespace std::placeholder; // 使用占位符 _1, _2, _3, ...

// binding functions:
auto fn_five = bind(my_divide, 10, 2);  // return 10/2,  且fn_five是个bind类的对象,里面赋值了op(my_divide), value1(10), value2(2)【参考上述binder2nd的过程解释】
cout << fn_five() << '\n';     // 5,  fn_five()表示类对象调用operator(),即 bind类对象进入其operator()的代码执行阶段,实际操作为my_divide(10, 2)
							   
auto fn_half = bind(my_divide, _1, 2);   //return x/2
cout << fn_half(10) << '\n';           // 5

auto fn_half = bind(my_divide, _2, _1);   //return y/x   占位符与参数一一对应
cout << fn_invert(10, 2) << '\n';           // 0.2


auto fn_half = bind<int>(my_divide, _1, _2);   //return int(x/y)  注意 bind<int>加了限定要求返回必须是int型 
cout << fn_invert(10, 3) << '\n';           // 3

// binding members:
MyPair ten_two{10, 2};  // 新特性的{ }赋值方式
// member function 实际有个argument: this,下面的_1便相当于this,即此处this为传入的ten_two对象,从而调用multiply()
auto bound_memfn = bind(&MyPair::multiply, _1);   //return x.multiply()
cout << bound_memfn(ten_two) << '\n';   // 20

auto bound_memdata = bind(&MyPair::a, ten_two); // return ten_two.a
cout << bound_memdata() << '\n';    // 10

auto bound_memdata = bind(&MyPair::b, _1); // return x.b
cout << bound_memdata2(ten_two) << '\n';    // 2
// 由以上知,binding members时需要使用 &取值符号!!


vector<int> v {15, 37, 94, 50, 73, 58, 28, 98};
int n = count_if(v.cbegin(), v.cend(), not1(bind2(less<int>(), 50)));  // cbegin()实际上为const begin()
cout << "n" << n << endl;  // 5

auto fn_ = bind(less<int>(), _1, 50);
cout << count_if(v.cbegin(), v.cend(), fn_) << endl;  // 3
cout << count_if(v.cbegin(), v.cend(), bind(less<int>(), _1, 50)) << endl;  // 3

四、Iterator Adapters

- reverse_iterator

在这里插入图片描述

template<class Iterator>
class reverse_iterator{
protected:
	Iterator current; // 对应的正向迭代器
public:
	//逆向迭代器的5种 associated types都和其对应的正向迭代器相同
	typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
	typedef typename iterator_traits<Iterator>::value_type value_type;
	typedef typename iterator_traits<Iterator>::difference_type difference_type;
	typedef typename iterator_traits<Iterator>::pointer pointer;
	typedef typename iterator_traits<Iterator>::reference reference;
	
	typedef Iterator iterator_type;  //代表正向迭代器
	typedef reverse_iterator<Iterator> self;  //代表逆向迭代器
public:
	explicit reverse_iterator(iterator_type x): current(x){}  // explicit防止调用系统默认构造函数
			 reverse_iterator(iterator_type x): current(x){}
	iterator_type base() const{
		return current;
	}
	reference operator*() const{
		Iterator tmp = current;
		return *--tmp;
	}
	// 以上为关键所在:对逆向迭代器就是将对应正向迭代器退一位取值
	pointer operator->() const{
		return &(operator*());  // 意义同上
	}
	
	// 前进变成后退,后退变成前进
	self& operator++(){
		--current;
		return *this;
	}
	self& operator--(){
		++current;
		return *this;
	}
	self operator+(difference_type n) const{
		return self(current - n);
	}
	self operator-(difference_type n) const{
		return self(current + n);
	}
};


reverse_iterator rbegin(){
	return reverse_iterator(end());
}
reverse_iterator rend(){
	return reverse_iterator(begin());
}
/*是否应该是
reverse_iterator<random_access_iterator_tag> rbegin(){ 即指定模板参数
	return reverse_iterator<random_access_iterator_tag>(end());
}
// 或者应该是有借用辅助函数进行参数类型的推导
*/

由上知,reverse_iterator是将原正向iterator的begin()赋值给rend(),end()赋值给rbegin(),然后在实现反向操作时,让rbegin()指向正向迭代器对应位置的退一位取值,且进行加动作时实际内部采取减操作,同样进行减操作时实际内部采取加操作

- inserter(注意不是insert)

template<class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result){
	while(first != last){
		*result = *first;
		++result;
		++first;
	}
	return result;
}

由copy的源码知,其进行操作时,若来源端的复制长度若大于于目的端的长度copy是不管的,因为first和last是来源端的迭代器指针,当目的端长度不够,其会将来源段多余的元素copy到其他位置去占用别处的内存,容易引发出错。若下面myvec长度不足7时则会报错:
在这里插入图片描述

因而考虑inserter来进行操作

// 辅助函数,帮助user使用insert_iterator,实际操作为推导Container类型
template<class Container, class Iterator>
inline insert_iterator<Container> inserter(Container& x, Iterator i){
	typedef typename Container::iterator iter;
	return insert_iterator<Container>(x, iter(i));
}

template<class Container>
class insert_iterator{
protected:
	Container* container;  // 底层容器
	typename Container::iterator iter;
public:
	typedef output_iterator_tag iterator_category; // 注意类型
	insert_iterator(Container& x, typename Container::iterator i): container(&x), iter(i){}
	insert_iterator<Container>& operator=(const typename Container::value_type& value){
		iter = container->insert(iter, value); //转调用insert()
		++iter;  // 令insert iterator随着target而移动
		return *this;
	}
	insert_iterator<Container>& operator* (){ 
		return *this; 
	}
    insert_iterator<Container>& operator++ (){ 
    	return *this; 
    }
 	insert_iterator<Container> operator++ (int){ 
 		return *this; 
 	}
};

list<int>foo, bar;
for(int i = 1; i <= 5; i++){
	foo.push_back(i);
	bar.push_back(i * 10);
}
list<int>::iterator it = foo.begin();
advance(it, 3); // 将it指针前进3个位置
copy(bar.begin(), bar.end(), inserter(foo, it));

在这里插入图片描述

copy(bar.begin(), bar.end(), inserter(foo, it))中的inserter(foo, it),调用辅助函数inserter,然后将f目标端Foo容器传进去,由编译器推导出参数Container的类型,并且由typedef typename Container::iterator iter进一步得出iterator的类型。

在调用insert_iterator时,insert_iterator<Container>(x, iter(i))先前置判断iter(i),即所传入迭代器是否符合对应类型。接着进入到insert_iterator的构造函数,将&Foo赋值给container,it 即==[foo.begin()+3]==赋值给iter记录下来,由此生成一个 insert_iterator<list<int>>类临时对象

此时,返回到copy源码段执行,其第三参数传入的是 insert_iterator<list<int>>类临时对象,进入到内部操作 *result = 时,实际相当于调用 insert_iterator<list<int>>类临时对象operator=(),则此时进入 operator=() 成员函数内部,传入参数value为*first【即来源端的指针bar.begin()所指向的元素值】,然后containerinsert_iterator<list<int>>类临时对象内部的成员变量 iter[foo.begin()+3],则container->insert()表示函数是在目标端容器Foo上的iter迭代器位置插入来源端的元素,并自动拓展空间【因为容器insert()函数在进行插入操作时可以自动扩展空间】。

注意:这里的copy调用仿函数insert_iterator是在其内部操作 *result = *first 才开始调用的!!

五、X adapters

- ostream_iterator

template<class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result){
	while(first != last){
		*result = *first;
		++result;
		++first;
	}
	return result;
}

template<class T, class charT = char, class traits = char_traits<charT>>
class ostream_iterator: public iterator<output_iterator_tag, void, void, void, void>{
	basic_ostream<charT, traits>* out_stream; // basic_ostream类型指针对象
	const charT* delim; // 字符类型指针对象
public:
	typedef charT char_type;  // char类型
	typedef traits traits_type;	// 萃取机的类型为char_traits<charT>
	typedef basic_ostream<charT, traits> ostream_type; // 声明basic_ostream<charT, traits>类型的别名为ostream_type
	// 一元参数形式的拷贝构造函数
	ostream_iterator(ostream_type& s): out_stream(&s), delim(0){}
	// 二元参数形式的拷贝构造函数
	ostream_iterator(ostream_type& s, const charT* delimiter): out_stream(&s), delim(delimiter){}
	// 拷贝赋值函数
	ostream_iterator(const ostream_iterator<T, charT, traits>& x) 
		: out_stream(x.out_stream), delim(x.delim){}
	~ostream_iterator(){}
	ostream_iterator<T, charT, traits>& operator=(const T& value){
		*out_stream << value;
		if(delim != 0)
			*out_stream << delim;
		return *this;
	}
	ostream_iterator<T, charT, traits>& operator*(){
		return *this;
	}
	ostream_iterator<T, charT, traits>& operator++(){
		return *this;
	}
	ostream_iterator<T, charT, traits>& operator++(int){
		return *this;
	}
}

// ostream_iterator example
#include<iostream>  // std::cout
#include<iterator>  // std::ostream_iterator
#include<vector>    // std::vector
#include<algorithm> // std::copy

int main(){
	std::vector<int> myvector;
	for(int i = 1; i < 10; ++i)
		myvector.push_back(i * 10);
	std::ostream_iterator<int> out_it(std::out, ","); // 生成迭代器对象并调用构造函数赋值
	std::copy(myvector.begin(), myvector.end(), out_it);
	return 0;
}

std::ostream_iterator<int> out_it(std::out, “,”)
调用ostream_iterator的构造函数ostream_iterator(ostream_type& s, const charT* delimiter): out_stream(&s), delim(delimiter){} 将&std::coutt的地址赋给out_stream【因为out_stream是指针类型,则后续若要取出cout即应 *out_stream】,将分隔符“,”赋值给delim,最终生成一个ostream_iterator迭代器对象。

std::copy(myvector.begin(), myvector.end(), out_it)
copy的第三参数是需要赋值到的目标端,传入的是上述生成的ostream_iterator迭代器对象,则进入到内部代码执行时,*result = 相当于 *out_it =。所以进入到ostream_iterator类内操作代码段,首先是operator*(),内部操作为返回*this指针本身【即返回 *out_it 】。然后out_it调用=号的重载函数,进入到operator=(),其内部 *out_stream即为cout,然后value则为来源端的 *first元素,最终将来源端的元素打印在屏幕上。接着将分隔符打印出来 *out_stream << delim;因而操作 *result = *first 实际相当于 cout << *first; & cout << “,”;】。而下面的++result操作也是进入ostream_iterator类内操作代码段operator++()注意不是operator++(int)的版本,只有result++才是调用operator++(int)的版本】,但内部只是返回*this指针本身【即返回 *out_it 】,无其他进一步操作。

最终通过上述操作,outstream_iterator与硬件屏幕(std::cout)绑定在一起,由copy()算法,将元素打印输出在屏幕上【结果为10,20,30,40,50,60,70,80,90】。

注意:这了ostream_iterator所修饰的是std::cout(所修饰的就是所存起来记录的 out_stream),而cout又是一种basic_ostream指针类型,所以ostream_iterator又称为basic_ostream的adapter修饰的是容器则称containers adapters,修饰的是仿函数则称functors adapters】。另外basic_ostream除了有cout外,还可以是指向文件操作的指针等等。

- istream_iterator

template<class T, class charT = char, class traits = char_traits<charT>, 
		 class Distance = ptrdiff_t>
class istream_iterator:
	public iterator<input_iterator_tag, T, Distance, const T*, const T&>{ // 继承父类iterator
	
	basic_istream<charT, traits>* in_stream;
	T value;
public:
	typedef charT char_type;
	typedef traits traits_type;
	typedef basic_istream<charT, traits> istream_type;
	// constructor
	istream_iterator(): in_stream(0){} // 表示若在创建对象时不指定参数,则in_stream赋值为0
	istream_iterator(istream_type& s): in_stream(&s){++*this;}
	istream_iterator(const istream_iterator<T, charT, traits, Distance>& x) // 拷贝赋值
		: in_stream(x.in_stream), value(x.value){}
	~istream_iterator(){}
	const T& operator*() const{
		return value;
	}
	const T* operator->() const{
		return &value;
	}
	istream_iterator<T, charT, traits, Distance>& operator++(){ // operator++()返回的是引用类型
		if(in_stream && !(*in_stream >> value))
			in_stream = 0;
		return *this;
	}
	istream_iterator<T, charT, traits, Distance> operator++(int){
		istream_iterator<T, charT, traits, Distance> tmp = *this;
		++*this;  // 调用上面的operator++()
		return tmp;
}
};
  • Example1
#include<iostream> // std::cin, std::cout
#include<iterator> // std::istream_iterator

int main(){
	double value1, value2;
	std::cout << "Please, insert two values:"; 
	std::istream_iterator<double> eos; // end-of-stream iterator,用来比对是否输入结束!
	std::istream_iterator<double> iit(std::cin); 
	/* 若 std::cout << "Please, insert two values:"; 写在
		  std::istream_iterator<double> iit(std::cin);之后,
		  则只有先输入数据后才会打印出"Please, insert two values:"这句话,
		  因为std::istream_iterator<double> iit(std::cin)一旦创建就立刻read,只有进行输入后才会进行后续操作!!
	*/
	if(iit != eos)
		value1 = *iit;
	++iit;
	if(iit != eos)
		value2 = *iit;
	std::cout << value1 << "*" << value2 << "=" << (value1 * value2) << ‘\n’;
	return 0;
}

std::istream_iterator<double> eos;
因为是空传入参数,所以调用istream_iterator()构造函数赋值in_stream为0,然后无其他操作。

std::istream_iterator iit(std::cin);
此时调用istream_iterator(istream_type& s)的构造函数创建的iie对象,将std::cin的地址赋值给in_stream记录下来,然后进入其内部动作++*this,而 *this则指iit自己本身,所以++*this则调用其operator++()的重载函数进入到 if(in_stream && !(*in_stream >> value)) 的判断,首先in_stream = &std::cin【即in_stream为std::cin的地址】不为空,然后!(*in_stream >> value))中*in_stream实际为解引用出std::cin【相当于!(std::cin >> value))】,此时则是在等待输入了:
1.若有输入【有输入则括号内为真,!(真) 即为假】,则将输入赋值到value记录下来。而此时因为if的最终条件为假,所以不会进入内部代码in_stream=0操作,返回iit【记录有in_stream = &std::cin,value = 第一次输入值】;
2.若无输入【无输入则括号内为假,!(假) 即为真】,同时value无输入赋值。而此时因为if的最终条件为真,所以进入内部代码in_stream=0操作,返回iit【记录有in_stream = &std::cin,value = 空】;

执行完std::istream_iterator iit(std::cin)后,进入下一步 if(iit != eos) value1 = *iit;,判断iit是否等于eos即输入结束,因为没有输入结束所以将进入内部操作value1=*iit,此时 *iit则为调用iit的operator*(),其内部操作位返回第一次输入的 value值。

接着执行++iit代码段,此时又是调用iit的operator++()再次进入到 if(in_stream && !(*in_stream >> value)) 的判断,而且在进行if!(*in_stream >> value))第二个条件判断时,就已经将第二次输入值记录在value上了【此时的 iit 记录有in_stream = &std::cin,value(已更新) = 第二次输入值】。然后进入if(iit != eos) value2 = *iit;,取出iit内部的value(第二次输入更新后的值)并赋值给value2。由此已完成对两次输入值的提取操作。

(注意:此时若还有后续 ++iit 操作,则在进入operator++()内部操作时,执行if(in_stream && !(*in_stream >> value)) 的判断,对于 !(*in_stream >> value) 因为无输入【因为前面代码提示只输入两个数且代码实际上也只提供了两次,所以一般输入完两个数后都按回车键表示输入结束。 无输入(输入结束)则括号内为假,!(假) 即为真】,同时value无输入赋值。而此时因为if的最终条件为真,所以进入内部代码 in_stream=0 操作,并返回iit【记录有in_stream = &std::cin,value = 空,所以此时的iit = eos表示输入结束了!】 则继续等待输入再进行后续操作!!

上述删除线是因为cin对空格和回车都不敏感,都不影响继续读入数据。

  • Example2
    在这里插入图片描述
    结合前面的inserter知,inserter(c, c.begin())是在传入的c容器的开始位置【即c.begin()】插入从 输入开始(iit)输入结束(eos) 的传入数据。
    首先在执行istream_iterator<int> iit(cin), eos;代码段,创建iit对象时就已经开始需要输入了【因为在调用class istream_iterator的构造函数创建iit对象时,就已经调用了operator++()并进入if()条件的判断,从而在条件判断的代码 !(*in_stream >> value)等待输入,才能进行后续操作】。在完成输入后才会完成创建对象 iit 的过程。接下来才会进行到copy()的代码执行段。在进入copy内部源码执行时,*first操作调用iitoperator*()【进入内部操作返回已经赋值并记录于value中的第一次输入的数据值】,而*result=则是上述inserter内容中的调用 insert_iterator<list<int>>类临时对象的operator=()实现将第一次输入数据值插入到c.begin()位置【并且此时容器c的插入位置指针也下移一位】。++result返回insert_iterator<list>类临时对象自己本身。++first则iit对象的operator++()继续等待输入下一个数据值:
    1.若无输入值【输入回车键】,则最终返回的iit【in_stream=0,value = 空】是等于eos的,则在下一次进入while()循环时条件不满足而退出;
    2.若有输入值,则最终返回的iit【in_stream=std::cin,value = 输入值】是不等于eos的,则下一次继续进入while()循环,继续插入所输入的vaule值,接着进入++first,继续等待输入(所以每一次++first,都会等待输入一次,才能进行后续操作)。。。

由上面的这些例子知,其都调用了copy()去实现自己的一些操作,但copy的源码都是写定不变的,所以只能通过Adapters去重载源码中的 *, =, ++ 等操作符从而实现不同的操作。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值