Q:

Что такое адаптер?

Читая книгу по STL я столкнулся с термином адаптер и сразу полез в поисковик что бы осветить этот вопрос и ни чего полезного не нашел.
В книге говорится что это реализация одного типа контейнера другим типом контейнера. В общем понятного мало.
Расскажите своими словами что такое адаптер в STL.

A:

Хочу начать с небольшого предисловия: такого понятия как STL в C++ не существует, есть стандартная библиотека и этого термина стоит придерживаться. Раньше термин STL использовали для обозначения стандартной библиотеки, но сейчас это считается моветоном.
Что же такое адаптер? Это, по существу, устоявшийся паттерн, который приходит к нам из реального мира. Мы берём одну сущность и адаптируем её к новым условиям через другую сущность. Безусловно, понятнее не стало. 
Что имеется в виду в книге? Вероятно там разговор идёт о стеке и прочих контейнерах-адапторах. Почему они адапторы? Потому что внутри себя используют полноценный контейнеры, такие как std::vector и std::deque, и адаптируют их интерфейс под другой интерфейс. К примеру, std::vector имеет методы push_back, insert и pop_back, но такие операции для стека не нужны, стеку нужны 3 операции(основные) top, pop и push. Но все эти операции реализованы через соответсвующие операции std::vector, который скрывается в недрах std::stack. Поэтому stack не выделяют как самостоятельный контейнер — он есть адаптер для std::vector.
Другими словами: адаптер это понятие, которое выходит далеко за рамки стандартной библиотеки C++ и, в целом, им можно пренебречь изучая C++, т.к. является ли контейнер адаптером или нет не является ключевой частью. Это интересно знать, но не более того. 

A:

Адаптировать - это значит приспосабливать. То есть приспосабливать существующую сущность, контейнер, итератор и т.д., , в новом контексте или для частной задачи.
Например, стандартный контейнер двусвязный список std::list имеет такие методы, как push_back, push_front, pop_back, pop_front, front, back.
Используя лишь подмножество методов, предоставляемых контейнером std::list, можно смоделировать поведение такой структуры данных, как стек.
В структуре данных стек данные организованы по принципу: последний вошел в стек - первый вышел из стека, то есть LIFO (last in, first out).
Обычно методы контейнера стек получают названия push, pop, top, как, например, в C++, или Push, Pop, Peek, как, например, в C# или другие названия. Но независимо от присвоенных названий методов их поведение семантически одно и то же.
Чтобы построить в C++ из списка стек, достаточно использовать методы либо push_front, pop_front, front, либо push_back, pop_back, back соответственно для методов стека push, pop, top.
Для этого просто в реализации данных методов стека следует вызывать соответствующие методы контейнера std::list.
Например, метод стека pop может быть реализован как вызов соответствующего метода контейнера std::list, который в примерах обозначен именем c от английского слова container:
void pop() { c.pop_back(); }

или
void pop() { c.pop_front(); }

Поэтому нет необходимости определять управление данными контейнера стек. Всю работу по управлению данными возьмет на себя контейнер std::list. Просто его методы, фактически, переименованы для адаптации к названиям методов контейнера стек.
Поэтому стек реализован не с нуля, а он просто является адаптацией класса std::list под логику работы стека, то есть стек - это адаптер контейнера.
Чтобы было возможно как можно больше последовательных контейнеров адаптировать под стек, было принято соглашение ограничиться методами последовательных контейнеров push_back, pop_back, и back, так как эти методы более широко распространены среди последовательных контейнеров. Например, контейнер std::vector не имеет методов push_front и pop_front, поэтому его нельзя было использовать для моделирования методов стека, используя именно эти методы последовательных контейнеров.
Однако стандартный последовательный контейнер std::forward_list, который был введен в стандарт C++ позже остальных стандартных последовательных контейнеров, не имеет методов push_back, pop_back и back. Поэтому адаптер контейнеров std::stack не может адаптировать этот контейнер для реализации стека.
Тем не менее я уже предложил Комитетам по стандартизации C++ включить специализацию класса std::stack для контейнера std::forward_list.
Это не представляет принципиальных трудностей сделать. 
Существует лишь одно несоответствии: класс std::forward_list не имеет метода size, который присутствует в адаптере контейнеров std::stack. С моей точки зрения это не принципиально.
Аналогичный подход используется для адаптеров итераторов. Примером такого адаптера итераторов является std::reverse_iterator. Он адаптирует оператор operator -- других итераторов таким образом, что когда используется оператор operator ++, то на самом деле вызывается оператор operator --. Это позволяет перебирать элементы контейнера или последовательности в обратном порядке, не меняя код, который основывается на применении оператора operator ++ .
Например, если у вас имеется функция, которая выводит в поток элементы некоторого контейнера посредством передачи в функцию диапазона элементов с помощью двух итератор, как, например
template <class ForwardIterator>
std::ostream & display( ForwardIterator first, 
                        ForwardIterator last,
                        std::ostream &os = std::cout )
{
    for ( ; first != last; ++first )
    {
        os << *first << ' ';
    }

    return os;
}

То, передавая реверсивные итераторы, вы могли бы, например, выводить элементы массива целых чисел в обратном порядке:
#include <iostream>
#include <iterator>

template <class ForwardIterator>
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 ) << std::endl;
    display( std::reverse_iterator<int *>( a + N ), std::reverse_iterator<int *>( a ) ) << std::endl;
}

Вывод программы на консоль:
0 1 2 3 4 5 6 7 8 9 
9 8 7 6 5 4 3 2 1 0 

В данной программе адаптер итераторов std::reverse_iterator адаптирует указатели типа int * для операций с ними в обратном порядке следования элементов массива. Он использует те методы указателей, которые уже определены и существуют для указателей.
Для разнообразия в качестве еще одного примера адаптера итераторов можете познакомиться с предложенным мной адаптером итераторов iterator_pair, который я описал в своей статье в журнале ACCU Overload #126 либо по ссылкам, приведенной на моей персональной странице здесь и здесь

