Adapt means to adapt. That is, to adapt an existing entity, container, iterator, etc., in a new context or for a particular task.
For example, the standard container double-linked list std::list has such methods as push_back , push_front , pop_back , pop_front , front, back .
Using only a subset of the methods provided by the std::list container, you can simulate the behavior of a data structure such as a stack.
In the data structure, the data stack is organized according to the principle: the last one entered the stack - the first one left the stack, that is, LIFO (last in, first out).
Usually the stack methods of the container get the names push , pop , top , as, for example, in C ++, or Push , Pop , Peek , as, for example, in C # or other names. But regardless of the assigned method names, their behavior is semantically the same.
To build a stack in C ++, it suffices to use the methods of either push_front , pop_front , front , or push_back , pop_back , back respectively, for the stack methods push , pop , top .
To do this, simply in the implementation of these methods of the stack should call the appropriate methods of the container std::list .
For example, the pop stack method can be implemented as a call to the corresponding container method std::list , which in the examples is indicated by the name c from the English word container :
void pop() { c.pop_back(); }
or
void pop() { c.pop_front(); }
Therefore, there is no need to define container data management stack. All data management will be done by the std::list container. Simply, its methods are, in fact, renamed to adapt to the names of the methods of the container stack.
Therefore, the stack is not implemented from scratch, but it is simply an adaptation of the class std::list for the logic of the stack, that is, the stack is a container adapter .
To make it possible to adapt as many consecutive containers as possible, it was agreed to limit the methods of sequential containers push_back , pop_back , and back , since these methods are more widely distributed among sequential containers. For example, the std::vector container does not have push_front and pop_front , so it could not be used to model stack methods using these methods of sequential containers.
However, the standard sequential container std::forward_list , which was introduced in the C ++ standard after the rest of the standard standard containers, does not have the push_back , pop_back and back methods. Therefore, the container adapter std::stack cannot adapt this container to implement the stack.
Nevertheless, I have already suggested that the C ++ Standardization Committees include a specialization of the std::stack class for the std::forward_list . This is not a fundamental difficulty to do.
There is only one inconsistency: the std::forward_list does not have a size method that is present in the std::stack container adapter. From my point of view, this is not important.
A similar approach is used for iterator adapters. An example of such an iterator adapter is std::reverse_iterator . It adapts the operator operator -- other iterators so that when operator ++ used, the operator operator ++ is actually called. This allows you to iterate through the elements of a container or sequence in reverse order, without changing the code, which is based on the application operator ++ .
For example, if you have a function that streams the elements of a container by passing a range of elements to the function using two iterators, such as
template <class ForwardIterator> std::ostream & display( ForwardIterator first, ForwardIterator last, std::ostream &os = std::cout ) { for ( ; first != last; ++first ) { os << *first << ' '; } return os; }
By passing in reverse iterators, you could, for example, output the elements of an array of integers in the reverse order:
#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; }
The output of the program to the console:
0 1 2 3 4 5 6 7 8 9 9 8 7 6 5 4 3 2 1 0
In this program, the std::reverse_iterator iterator adapter adapts int * type pointers for operations on them in the reverse order of the array elements. It uses those pointer methods that are already defined and exist for pointers.
For a change as another example of the adapter of iterators, you can get acquainted with the iterator adapter iterator_pair that I proposed, which I described in my article in ACCU Overload # 126 magazine or via the links on my personal page here and here