Adapters
An Adapter is a component that modifies the interface of another component.
One example is a reverse_iterator, which adapts an iterator type into a type of iterator with all the capabilities of the original, but with the direction of traversal reversed.
You can obtain a reverse_iterator by calling a container’s rbegin() or rend() methods.
//
// main.cpp
// STL Adapters
//
// Created by Bryan Higgs on 10/23/24.
//
#include <iostream>
#include <vector> // For vector
#include <string> // For string
#include <algorithm> // For for_each()
void display(std::string x)
{
std::cout << x << std::endl;
}
int main(int argc, const char * argv[])
{
std::string values[] =
{"Rose ", "Daffodil ", "Orchid ", "Tulip "};
size_t len = sizeof(values)/sizeof(values[0]);
// Initialize vector using pointer iterator
std::vector<std::string> v(&values[0], &values[len]);
// Use a regular iterator
for_each(v.begin(), v.end(), display);
std::cout << std::endl;
// Use a reverse_iterator
for_each(v.rbegin(), v.rend(), display);
return 0;
}… which outputs the following:
Rose
Daffodil
Orchid
Tulip
Tulip
Orchid
Daffodil
Rose
Program ended with exit code: 0
The for_each Loop
Note the use of a for_each loop:
for_each (InputIterator first, InputIterator last, Function fn)
first : The beginning position from where function operations are to be executed.
last : The ending position until where function has to be executed.
fn : The 3rd argument is a function or an object function specifying the operation to be applied to each element.for_each is defined in
#include<algorithm>
The calls to rbegin() and rend() return iterators of type vector<string>::reverse_iterator, which is defined as part of the vector interface.
We could have used the following directly in the program:
reverse_iterator< vector<string>::iterator >
start( v.end() ), finish( v.begin() );
for_each(start, finish, display);Container Adapters
With a Container Adapter, you can choose the interface you wish, and also the underlying structure.
STL supplies three Container Adapters:
- stack : A Last-In, First-Out (LIFO) structure
- queue : Supports insertions at the back, and removals from the front.
- priority_queue : Supports insertions in sorted order, and removals from the front.
The stack Container Adapter
Here’s an example of the use of a stack container adapter:
//
// main.cpp
// STL Container Adapters
//
// Created by Bryan Higgs on 10/23/24.
//
#include <iostream>
#include <stack>
int main(int argc, const char * argv[])
{
std::stack< const char * > s;
// Uses default deque implementation
s.push("Nashua");
s.push("Manchester");
s.push("Hollis");
s.push("Milford");
s.push("Amherst");
while (!s.empty())
{
std::cout << s.top() << std::endl;
s.pop(); // returns no value
}
return 0;
}… which outputs:
Amherst
Milford
Hollis
Manchester
Nashua
Program ended with exit code: 0
Or you can override the default implementation to use any of the sequence containers (vector, deque, or list):
//
// main.cpp
// STL Container Adapters
//
// Created by Bryan Higgs on 10/23/24.
//
#include <iostream>
#include <vector>
#include <stack>
int main(int argc, const char * argv[])
{
//std::stack< const char * > s;
// Uses default deque implementation
std::stack< const char *, std::vector<const char *> > s;
// uses vector
s.push("Nashua");
s.push("Manchester");
s.push("Hollis");
s.push("Milford");
s.push("Amherst");
while (!s.empty())
{
std::cout << s.top() << std::endl;
s.pop(); // returns no value
}
return 0;
}… which outputs:
Amherst
Milford
Hollis
Manchester
Nashua
Program ended with exit code: 0
The queue Container Adapter
A queue container adapter may be implemented using either list or deque (the default).
Here we use a list:
//
// main.cpp
// STL Container Adapters
//
// Created by Bryan Higgs on 10/23/24.
//
#include <iostream>
#include <list>
#include <queue>
int main(int argc, const char * argv[])
{
std::queue< const char *, std::list<const char *> > q;
// Uses list
q.push("Nashua");
q.push("Manchester");
q.push("Hollis");
q.push("Milford");
q.push("Amherst");
while (!q.empty())
{
std::cout << q.front() << std::endl;
q.pop(); // returns no value
}
return 0;
}… which outputs:
Nashua
Manchester
Hollis
Milford
Amherst
Program ended with exit code: 0
The priority_queue Container Adapter
A priority_queue container adapter may be implemented using a deque or a vector (the default is vector):
//
// main.cpp
// STL Container Adapters
//
// Created by Bryan Higgs on 10/23/24.
//
#include <iostream>
#include <vector>
#include <queue>
#include <string>
int main(int argc, const char * argv[])
{
std::priority_queue< std::string > q; // Uses vector, less<T>
q.push("Nashua");
q.push("Manchester");
q.push("Hollis");
q.push("Milford");
q.push("Amherst");
while (!q.empty())
{
std::cout << q.top() << std::endl;
q.pop();
}
return 0;
}… which outputs:
Nashua
Milford
Manchester
Hollis
Amherst
Program ended with exit code: 0
Or we can change the priority ordering:
//
// main.cpp
// STL Container Adapters
//
// Created by Bryan Higgs on 10/23/24.
//
#include <iostream>
#include <vector>
#include <queue>
#include <string>
int main(int argc, const char * argv[])
{
//std::priority_queue< std::string > q; // Uses vector, less<T>
std::priority_queue<std::string,
std::vector<std::string>,
std::greater<std::string> > q;
q.push("Nashua");
q.push("Manchester");
q.push("Hollis");
q.push("Milford");
q.push("Amherst");
while (!q.empty())
{
std::cout << q.top() << std::endl;
q.pop();
}
return 0;
}… which outputs:
Amherst
Hollis
Manchester
Milford
Nashua
Program ended with exit code: 0