Parent directory
Makefile
concept.cpp
itraits.cpp
stl3.cpp
CC = g++
CXX = g++
CFLAGS = -Wall
CXXFLAGS = -Wall -std=c++17
executables = stl3 itraits
.PHONY: default
default: $(executables)
.PHONY: clean
clean:
rm -f a.out core *.o $(executables)
.PHONY: all
all: clean default
#include <array>
#include <vector>
#include <deque>
#include <list>
#include <forward_list>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
void print_int(int x) { cout << x << " "; }
template <bidirectional_iterator I>
void MyReverse(I b, I e)
{
while ((b != e) && (b != --e)) {
std::iter_swap(b,e);
++b;
}
}
template <input_iterator I>
void MyReverse(I b, I e)
{
throw invalid_argument("BidirectionalIterator required");
}
template <typename I>
void MyReverse(I b, I e)
{
throw invalid_argument("You are not even trying...");
}
int main() {
try {
list v { 100, 101, 102, 103, 104 };
//forward_list v { 100, 101, 102, 103, 104 };
MyReverse(v.begin(), v.end());
//MyReverse(100, 200);
for_each(v.begin(), v.end(), &print_int); cout << '\n';
}
catch (const exception& e) {
cerr << e.what() << '\n';
}
}
#include <array>
#include <vector>
#include <deque>
#include <list>
#include <forward_list>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
// Pretty much the same as std::for_each
template <typename I, typename F>
void For_Each(I b, I e, F f)
{
while (b != e) {
f(*b);
++b;
}
}
void print_int(int x) { cout << x << " "; }
/*
template <typename I>
void MyReverse(I b, I e)
{
while ((b != e) && (b != --e)) {
std::iter_swap(b,e);
++b;
}
}
*/
template <typename I>
void __doMyReverse(I b, I e, bidirectional_iterator_tag)
{
while ((b != e) && (b != --e)) {
std::iter_swap(b,e);
++b;
}
}
template <typename I>
void __doMyReverse(I b, I e, forward_iterator_tag)
{
throw invalid_argument("BidirectionalIterator required");
}
template <typename I>
void MyReverse(I b, I e)
{
__doMyReverse(b, e, typename I::iterator_category());
// The following change makes this work for C pointers as well because
// iterator_traits<T*>::iterator_category = random_access_iterator_tag
//
// __doMyReverse(b,e,typename iterator_traits<I>::iterator_category())
}
int main()
{
try {
//list v { 100, 101, 102, 103, 104 };
forward_list v { 100, 101, 102, 103, 104 };
//deque v { 100, 101, 102, 103, 104 };
MyReverse(v.begin(), v.end());
//reverse(v.begin(), v.end());
For_Each(v.begin(), v.end(), &print_int); cout << "\n";
}
catch (const exception& e) {
cerr << e.what() << '\n';
}
}
/*
Lecture outline:
1. MyReverse() vs. std::reverse()
- different levels of error reporting on forward_list
2. Introduction to Template Metaprogramming: tag dispatching
- Container<T>::iterator_category type
- why is deque<T>::iterator_category bidirectional_iterator_tag?
- iterator_traits<I> and template specialization
3. Concepts in C++20
- "template <bidirectional_iterator I>" instead of
"template <typename I>"
*/
#include <array>
#include <vector>
#include <deque>
#include <list>
#include <forward_list>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
template <typename Container>
struct IteratorThatPushes
{
Container& c;
using iterator_category = output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
explicit IteratorThatPushes(Container& c) : c(c) {}
IteratorThatPushes& operator*() { return *this; }
IteratorThatPushes& operator++() { return *this; }
IteratorThatPushes operator++(int) { return *this; }
IteratorThatPushes& operator=(const typename Container::value_type& x)
{
c.push_back(x);
return *this;
}
};
// Pretty much the same as std::for_each
template <typename I, typename F>
void For_Each(I b, I e, F f)
{
while (b != e) {
f(*b);
++b;
}
}
void print_int(int x) { cout << x << " "; }
int main()
{
vector<int> v1 { 100, 101, 102, 103, 104 };
vector<int> v2;
copy(v1.begin(), v1.end(), v2.begin());
For_Each(v2.begin(), v2.end(), &print_int); cout << '\n';
}
/*
Lecture outline:
1. copy(v1.begin(), v1.end(), v2.begin());
- "For a container, use the ()-initializer syntax for sizes and the
{}-initializer syntax for lists of elements" - Bjarne Stroustrup
code:
vector<int> v2;
vector<int> v2{5};
vector<int> v2(5);
2. vector( std::initializer_list<T> init );
3. iterator that calls push_back()
code:
vector<int> v2;
copy(v1.begin(), v1.end(), IteratorThatPushes<vector<int>>{v2});
copy(v1.begin(), v1.end(), IteratorThatPushes{v2});
copy(v1.begin(), v1.end(), back_inserter(v2));
4. ostream_iterator
code:
ostream_iterator<int> oi {cout, "\n"};
copy(v2.begin(), v2.end(), oi);
5. istream_iterator
code:
vector<int> v2;
istream_iterator<int> iib {cin};
istream_iterator<int> iie {};
copy(iib, iie, back_inserter(v2));
reverse(v2.begin(), v2.end());
5. Iterator categories
- LegacyInputIterator
- LegacyOutputIterator
- LegacyForwardIterator
- LegacyBidirectionalIterator
- LegacyRandomAccessIterator
- LegacyContiguousIterator (since C++17)
*/