Слайд 2Типы адаптеров итераторов 
Адаптеры - шаблонные классы, которые обеспечивают отображения интерфейса. Например,

insert_iterator обеспечивает контейнер интерфейсом итератора вывода.
Иногда адаптеры итераторов называют адаптерами экземпляра для итераторов.
Для итераторов существуют два основных типа адаптеров: 
- итераторы вставки (insert) 
- обратные (reverse) итераторы. 
Кроме того, имеются адаптеры потоковых итераторов. Со стандарта С++11 появился адаптер итератора перемещения.
Слайд 3Вставка 
Итератор вставки inserter является общим в том смысле, что мы указываем

позицию, в которой будет происходить вставка элементов. Если вставка в контейнер L должна происходить в конце, мы можем написать L.end(), как в следующей программе:
Слайд 4Пример 
	// Копирование вектора с помощью итератора вставки.
#include 
#include 
#include 
using namespace

std;
int main() { 
	int a [4] = {10, 20, 30, 40};
 	vector v(a, a+4); 
	list L(2, 123);
copy( v.begin(), v.end(), inserter (L, L.end()));
	list::iterator i;
for (i=L.begin(); i != L.end(); ++i)
	cout *i << " "; 	// Вывод: 123 123 10 20 30 40 
	cout << endl;
 return 0;
}
Слайд 5Еще пример
#include  
#include  
#include  
#include  
int main ()

{
 std::list foo, bar;
 for (int i=1; i<=5; i++)
 { foo.push_back(i); bar.push_back(i*10); }
 std::list::iterator it = foo.begin();
 advance (it,3);
 std::copy ( bar.begin(), bar.end(), std::inserter (foo, it) );
 std::cout << "foo contains:";
 for ( std::list::iterator it = foo.begin(); it!= foo.end(); ++it )
 std::cout << ' ' << *it;
 std::cout << '\n'; return 0; }
Output: 
1 2 3 10 20 30 40 50 4 5
Слайд 6Поскольку вставка в конце контейнера является часто встречающейся операцией, для нее существует

специальный итератор вставки, называемый back_inserter. 
Приведенная выше программа работает точно так же, если мы заменим вызов алгоритма сору на вызов:
copy ( v. begin () , v.end() , back_inserter (L) ) ;
Так как back_inserter всегда добавляет элементы в конец, он требует в качестве единственного аргумента контейнер.
Слайд 7Пример back_inserter
#include  
#include  
#include  
#include  
int main ()

{
 std::vector foo, bar;
 for (int i=1; i<=5; i++)
 { foo.push_back(i); bar.push_back(i*10); }
 std::copy (bar.begin(), bar.end(), back_inserter(foo));
 std::cout << "foo contains:";
 for ( std::vector::iterator it = foo.begin(); it!= foo.end(); ++it )
	 std::cout << ‘ ' << *it;
 std::cout << '\n'; return 0;
}
Output: 
foo contains: 1 2 3 4 5 10 20 30 40 50
Слайд 8Еще один итератор вставки, front_inserter, работает специфическим образом: каждый вставляемый элемент помещается

в начале контейнера, что приводит к тому, что значения следуют в обратном порядке. Например, если заменим в предыдущем примере back_inserter на front_inserter
copy (v. begin () , v.end(), front_inserter (L)) ;
 	будут выведены следующие значения:
50 40 30 20 10 1 2 3 4 5 
Мы также можем использовать итераторы вставки другими способами. Например, вместо
L.push_front(111); 
L.push_back(999); 
можно написать:
*front_inserter (L)=111; *back_inserter (L)=999; 
Слайд 9Обратные итераторы 
vector::iterator vector::reverse_iterator 
vector::const_iterator vector::const_reverse_iterator
Обратный итератор может использоваться в следующем фрагменте

для вывода всех элементов вектора v в обратном порядке:
	vector::reverse_iterator i; 
for ( i=v.rbegin() ; i != v.rend() ; ++ i) 
	cout << * i << " ";
Типы итераторов, имена которых начинаются с const, нужны, когда контейнер сам имеет атрибут const:
Слайд 10		// const_iterator и const_reverse_iterator
#include  
#include 
using namespace std;
void showlist (const list

&x) { 		// Вперед:
		list
::const_iterator i;
 for (i=x.begin(); i != x.end(); ++ i)
		cout << * i << " ";
 cout << endl;					 // Вывод: 10 20 30 
 									// Назад:
list::const_reverse_iterator j; 
for ( j=x.rbegin(); j != x.rend() ; ++j)
cout << * j << " "; cout << endl; // Вывод: 30 20 10
} 
Пример
Слайд 11int main() { 
	 list L;
		L.push_back(10); L.push_back(20); L.push_back(30);
		showlist (L); 
	 return 0;
}
Чтобы

удалить префикс const_, встречающийся два раза в функции showlist, мы должны также удалить ключевое слово const, имеющееся в первой строке этой функции. 
Поскольку функция не модифицирует список, передаваемый ей в качестве параметра, хороший стиль программирования требует наличия const в этом примере.
Слайд 12Еще о реверсивных (обратных) итераторах 
Реверсивный итератор адаптирует оператор operator-- других итераторов

таким образом, что когда используется оператор operator++, то на самом деле вызывается оператор operator--. Это позволяет перебирать элементы контейнера или последовательности в обратном порядке, не меняя код, который основывается на применении оператора operator++ .
Например, если имеется функция, которая выводит в поток элементы некоторого контейнера посредством передачи в функцию диапазона элементов с помощью двух итераторов.
То, передавая реверсивные итераторы, можно, например, выводить элементы массива целых чисел в обратном порядке.
В следующем примере адаптер итераторов std::reverse_iterator адаптирует указатели типа int * для операций с ними в обратном порядке следования элементов массива. Он использует те методы указателей, которые уже определены и существуют для указателей.
(по материалу из https://ru.stackoverflow.com/questions/479987/Что-такое-адаптер)
Слайд 13#include 
#include 
template 
std::ostream & display ( ForwardIterator first, ForwardIterator last,

std::ostream &os = std::cout ) {
 for ( ; first != last; ++first ) { 
 os << *first << ' ';
 }
 return os;
}
int main() {
 const size_t N = 10;
 int a[N] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 display( a, a + N ) << “ и ”;
 display( std::reverse_iterator( a + N ), 
			 std::reverse_iterator( a ) ) << std::endl;
} // Вывод : 0 1 2 3 4 5 6 7 8 9 и 9 8 7 6 5 4 3 2 1 0 
Слайд 14Адаптер итератора перемещения 
std::move_iterator
Этот класс адаптирует итератор так, чтобы разыменование производило ссылки

на rvalue (как если было бы применено std::move ), а остальные операции ведут себя как в обычном итераторе.
Этот адаптер итератора хранит внутреннюю копию итератора (известного как базовый итератор), на которой отражаются все операции. 
Копию базового итератора с текущим состоянием можно получить в любое время, вызвав элемент base().
Слайд 15move_iterator
#include  
#include  
#include  
#include  
#include  
int main

() {
 std::vector foo (3);
 std::vector bar {"one","two","three"};
 typedef std::vector::iterator Iter;
 std::copy ( std::move_iterator(bar.begin()),
 std::move_iterator(bar.end()),
 foo.begin() );
 bar.clear(); 
 	std::cout << "foo:";
 for (std::string& x : foo) std::cout << ' ' << x;
 std::cout << '\n'; return 0;}
Output: foo: one two three
Слайд 16std::make_move_iterator
#include  // std::cout
#include  // std::make_move_iterator
#include  // std::vector
#include  //

std::string
#include 
 // std::copy
int main () {
 std::vector foo (3);
 std::vector bar {"one","two","three"};
 std::copy ( make_move_iterator (bar.begin()),
 make_move_iterator (bar.end()),
 foo.begin() );
bar.clear(); // бар теперь содержит неопределённые значения; 
 std::cout << "foo:";
 for (std::string& x : foo) std::cout << ' ' << x;
 std::cout << '\n';
 return 0;
} 
Output: foo: one two three
Слайд 17Адаптеры потоковых итераторов
Эти адаптеры делают удобным работу с потоками ввода и вывода,

а также буферами потоков, представляя их в виде итераторов ввода и вывода: std::istream_iterator, std::ostream_iterator, std::istreambuf_iterator и std::ostreambuf_iterator.
В следующем примере показано, как тип std::istream_iterator можно использовать для чтения набора значений из стандартного потока ввода std::cin, а тип std::ostream_iterator - для записи этого набора после сортировки в строковый поток.
Слайд 18Пример
#include
#include
#include
#include
#include
#include
int _tmain(int argc, _TCHAR* argv[ ]) {
	std::vector values; 
	std::stringstream sstm;
 std::string s;
std::copy(std::istream_iterator(std::cin)

		// Прочитать значения 
 , std::istream_iterator(), std::back_inserter(values));
std::sort(values.begin(), values.end());			// Отсортировать значения
 std::copy(values.begin(), values.end() , std::ostream_iterator(sstm, " ")); // Вывод
 s= sstm.str(); // передать из потока в строку
 std::cout<return 0;
}
Слайд 19ostream_iterator и istream_iterator
#include  
#include  
#include  
#include  
int main

() {
 std::vector myvector;
 for (int i=1; i<10; ++i) myvector.push_back (i*10);
 std::ostream_iterator out_it (std::cout,", ");
 std::copy ( myvector.begin(), myvector.end(), out_it );
 return 0;
}
Output: 10, 20, 30, 40, 50, 60, 70, 80, 90,
Слайд 20Пример istream_iterator
#include  // std::cin, std::cout
#include  // std::istream_iterator
int main () {

double value1, value2;
 std::cout << "Please, insert two values: ";
 std::istream_iterator  eos; // концевой итератор 
 std::istream_iterator  iit (std::cin); // stdin итератор 
 if (iit != eos) value1=*iit;
 ++iit;
 if (iit !=eos) value2=*iit;
 std::cout << value1 << "*" << value2 << "=" << (value1*value2) << '\n';
 return 0;
}
Possible output:
Please, insert two values: 2 32
2*32=64
Слайд 21Чтение из файла
#include
#include
#include
#include  
using namespace std;
 	typedef istream_iterator istream_iter;
int main() {
	vector

a;
	ifstream file("example.txt"); // содержимое файла: 20 30 40 50
if (file.fail()) { 
	cout << "Cannot open file example.txt.\n"; 
return 1;
 }
	copy(istream_iter(file), istream_iter(), 
			inserter(a, a.begin() )); // копируем из файла прямо в вектор
		copy(a.begin(), a.end(),
 			ostream_iterator(cout, " ")); // копируем из вектора прямо в cout
 cout << endl; return 0;
}
Слайд 22std::istreambuf_iterator
Класс istreambuf_iterator очень похож на istream_iterator. Однако вместо форматированного ввода произвольных типов

он читает одиночные символы из потока ввода. 
Это адаптер итератора ввода, и, как и istream_iterator, istreambuf_iterator достигает специального значения "за последним элементом", когда доходит до конца потока.
Например.
В буфер читаются все оставшиеся символы из стандартного потока ввода.
int main() {
 istreambuf_iterator first(cin);
 istreambuf_iterator end_of_stream;
 vector buffer (first, end_of_stream);
}
Слайд 23std:: ostreambuf_iterator 
Класс ostreambuf_iterator адаптер итератора вывода, который записывает символы в поток

вывода. 
В отличие от ostream_iterator, вместо обобщенного форматированного вывода произвольных типов он записывает одиночные символы с помощью функции члена sputc класса streambuf.
Например:
int main() { 
	string s = "This is a test\n“;
	copy(s.begin(), s.end(), ostreambuf_iterator  (cout) );
}
Слайд 24Пример
#include  // std::cin, std::cout
#include  // std::istreambuf_iterator
#include  // std::string
int main

() {
 std::istreambuf_iterator eos; // end-of-range iterator
 std::istreambuf_iterator iit (std::cin.rdbuf()); // stdin iterator
 std::string mystring;
 std::cout << "Please, enter your name: ";
 while (iit !=eos && *iit != '\n') mystring += *iit++;
 std::cout << "Your name is " << mystring << ".\n";
 return 0;
}
Possible output:
Please, enter your name: Andrey
Your name is Andrey
Слайд 25Пример
#include  // std::cin, std::cout
#include  // std::ostreambuf_iterator
#include  // std::string
#include 

// std::copy
int main () {
 std::string mystring ("Some text here...\n");
 std::ostreambuf_iterator out_it (std::cout); // stdout iterator
 std::copy ( mystring.begin(), mystring.end(), out_it);
 return 0;
}
Слайд 26Пример из книги С. Мейерса
Совет 29. Рассмотрите возможность использования istreambuf_iterator при посимвольном

вводе (“Эффективное использование STL”).
Предположим, вы хотите скопировать текстовый файл в объект string. На первый взгляд следующее решение выглядит вполне разумно:
ifstream inputfile ( "interestingData.txt");
		// Прочитать inputFile в fileData
string fileData ( istream_iterator(inputFile) , istream_iterator() ); 
Но вскоре выясняется, что приведенный синтаксис не копирует в строку пропуски (whitespace), входящие в файл. 
Это объясняется тем, что istream_iterator производит непосредственное чтение функциями operator, а эти функции по умолчанию не читают пропуски.
Слайд 27Чтобы сохранить пропуски, входящие в файл, достаточно включить режим чтения пропусков сбросом

флага skipws для входного потока:
ifstream inputfile ("interestingData.txt");
inputFile.unset(ios::skipws); // Включить режим чтения пропусков в inputFile
string fileData( istream_iterator(inputFile) , istream_iterator() );	 
Теперь все символы inputFile копируются в fileData.
Кроме того, может выясниться, что копирование происходит не так быстро, как хотелось бы. 
Функции operator<<, от которых зависит работа istream_iterator, производят форматный ввод, а это означает, что каждый вызов сопровождается многочисленными служебными операциями. 
Слайд 28Более эффективное решение основано на использовании итератора istreambuf_iterator. Итераторы istreambuf_iterator работают аналогично

istream_iterator, но если объекты istream_iterator читают отдельные символы из входного потока оператором , то объекты istreambuf_iterator обращаются прямо к буферу потока и непосредственно читают следующий символ (выражаясь точнее, объект istreambuf_iterator  читает следующий символ из входного потока s вызовом
 s.rdbuf ( )->sgetc( );
ifstream inputfile ( "interestingData.txt"); 
string fileData ( istreambuf_iterator(inputfile ), 
 istreambuf_iterator() );
На этот раз сбрасывать флаг skipws не нужно, итераторы istreambuf_iterator никогда не пропускают символы при вводе и просто возвращают следующий символ из буфера.
Слайд 29Мои опыты
// рекомендую со следующей программой поработать самостоятельно
// в ней разные варианты

- изучите
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
template 
__int64 time_call(Function&& f) // для подсчета времени
{
 __int64 begin = GetTickCount();
 f();
 return GetTickCount() - begin;
}
Слайд 30template< typename Fwd>
void printData (Fwd first, Fwd last, char* delim =",", ostream&

out = cout ){
 while (first != last) { 
		 out << *first; 
		if (++first != last)
			out << delim << ' ';
 }
 out<}
template
void printAllData (const C& c, char* delim="," , ostream& out = cout){
 	printData( c.begin( ), c.end( ), delim, out); 
}
Слайд 31int _tmain(int argc, _TCHAR* argv[ ]){
 int i;
 setlocale(LC_ALL, "ru");
 cout<<"введите вариант
![int _tmain(int argc, _TCHAR* argv[ ]){ int i; setlocale(LC_ALL, "ru"); cout cin>>i;](/_ipx/f_webp&q_80&fit_contain&s_1440x1080/imagesDir/jpg/1022649/slide-30.jpg)
алгоритма"<< endl;
 cin>>i;
 const int COUNT =10000;
if(i==0){
ifstream inputfile ;
__int64 begin = GetTickCount(); 
 string fileData;
for(int i=0;i< COUNT; i++){
 inputfile.open ( "data.txt");
 fileData = string( istream_iterator( inputfile) , 
 istream_iterator() ); 
 inputfile.close();
 }
 wcout<< L"serial: " << GetTickCount() - begin<< endl;;
 cout<< fileData;
} // 0
Слайд 32else if(i==1){
 string fileData ;
__int64 begin = GetTickCount(); // сравнение времени выполнения

for(int i=0;i< COUNT; i++){
 fileData = string( istreambuf_iterator( ifstream ( "data.txt") ) , 
 istreambuf_iterator() ); 
 }
 wcout<< L"serial: " << GetTickCount() - begin<< endl;
 cout<< fileData;
} // 1
else if(i==2){
 string fileData ;
__int64 begin = GetTickCount(); // использование умного указателя (след. сем.)
 for( int i=0;i< COUNT; i++){
 fileData = string( ( istreambuf_iterator( *( unique_ptr ( new 
				 ifstream("data.txt") )) )), 
			 istreambuf_iterator() ); // вывод
 }
 wcout<< L"serial: " << GetTickCount() - begin<< endl;
 cout<< fileData;
} // 2
Слайд 33else if(i==3) {
 string fileData ;
ifstream dataFile ( "data.txt"); // многострочное чтение

файла
typedef int T ;
istream_iterator dataBegin (dataFile);
istream_iterator dataEnd;
list data(dataBegin, dataEnd);
	 printAllData ( data," ");
} // 3
else if(i==4) {
 // одной строкой читаем собственный файл в строку и выводим на консоль
 cout<< string( ( istreambuf_iterator( *( unique_ptr 
						( new ifstream(__FILE__ ) )) )), // __FILE__
				 istreambuf_iterator() ); 
} 
Слайд 34else if(i==5) {
 // одной строкой читаем файл и сразу кладем токены

в список
list< string> data( (istream_iterator< string> ( ifstream ( "data.txt") )), 
				 istream_iterator< string>() );
 printAllData ( data," "); // и печатаем из списка
 }
else {
 cout<< string ( ( istreambuf_iterator( ifstream (__FILE__ ) ) ), // __FILE__
 istreambuf_iterator() ); // читаем файл с помощью istreambuf_iterator
 cout<< string("");
 }
return 0;
}