Parent directory Makefile concept.cpp itraits.cpp stl3.cpp
Download
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) */