int_range_iterator now models the random access iterator concept completely. Conformance is tested using the Boost concept check library.
#include <iostream> #include <iterator> #include <string> #include <boost/concept_check.hpp> class int_range_iterator : public std::iterator<std::random_access_iterator_tag, int, ptrdiff_t, const int*, const int&> { public: int_range_iterator(int i = 0) : i_(i) {} // implicit copy constructor, copy assignment and destructor const int& operator* () const { return i_; } pointer operator->() const { return &i_; } int_range_iterator& operator++ () { ++i_; return *this; } int_range_iterator operator++ (int) { int_range_iterator tmp = *this; ++*this; return tmp; } int_range_iterator& operator+=(difference_type n) { i_+=n; return *this; } int_range_iterator& operator--() { --i_; return *this; } int_range_iterator operator--(int) { int_range_iterator tmp = *this; --*this; return tmp; } int_range_iterator& operator-=(difference_type n) { i_-=n; return *this; } friend int_range_iterator operator-(int_range_iterator iter, difference_type n) { return iter-= n; } friend int operator-(int_range_iterator iter1, int_range_iterator iter2) { return iter1.i_ - iter2.i_; } friend int_range_iterator operator+(int_range_iterator iter, difference_type n) { return iter+= n; } friend int_range_iterator operator+(difference_type n, int_range_iterator iter) { return iter+=n; } int operator[](difference_type n) { return i_+n; } bool operator== (const int_range_iterator& other) const { return i_ == other.i_; } bool operator!= (const int_range_iterator& other) const { return i_ != other.i_; } bool operator<(const int_range_iterator& other) const { return i_ < other.i_; } bool operator>(const int_range_iterator& other) const { return i_ > other.i_; } bool operator<=(const int_range_iterator& other) const { return i_ <= other.i_; } bool operator>=(const int_range_iterator& other) const { return i_ >= other.i_; } private: int i_; }; int main() { boost::function_requires<boost::RandomAccessIteratorConcept<int_range_iterator> >(); return 0; }
adjacent_find
#include <iterator> #include <algorithm> #include <iostream> // because of using input iterators, we have to return an iterator // to the latter one of the adjacent values template <class InputIterator> InputIterator adjacent_find (InputIterator begin, InputIterator end) { if (begin == end) return end; typename std::iterator_traits<InputIterator>::value_type value = *begin; while (++begin != end) { if (*begin == value) return begin; value = *begin; } return end; } bool check(std::string s) { std::string::iterator i, j; i = std::adjacent_find(s.begin(), s.end()); j = ::adjacent_find(s.begin(), s.end()); return (i == s.end() && j == s.end()) || i+1 == j; } int main() { assert(check(std::string(""))); assert(check(std::string("a"))); assert(check(std::string("abbc"))); assert(check(std::string("abcdef"))); assert(check(std::string("abcdee"))); assert(check(std::string("aaabsdf"))); std::cin.unsetf(std::ios::skipws); std::istream_iterator<char> i = ::adjacent_find(std::istream_iterator<char>(std::cin), std::istream_iterator<char>()); std::copy(i, std::istream_iterator<char>(), std::ostream_iterator<char>(std::cout)); return 0; }
Because of input iterators, we have to return an iterator to the latter one of the two adjacent values.
The original version of adjacent_find required its value type to be equality comparable. Our new version requires, in addition, the assignable concept.
reverse_word_order
#include <iostream> #include <iterator> #include <string> #include <list> template <class BidirectionalIterator, class T, class OutputIterator> OutputIterator reverse_word_order(BidirectionalIterator begin, BidirectionalIterator end, OutputIterator result, const T& separator) { typedef std::reverse_iterator<BidirectionalIterator> riterator; riterator rbegin(end); riterator rend(begin); riterator i; while ((i=find(rbegin, rend, separator)) != rend) { result = std::copy(i.base(), rbegin.base(), result); *result++ = separator; rbegin=i; ++rbegin; } result = std::copy(i.base(), rbegin.base(), result); return result; } int main() { std::string str("Are these words?"); // it really works for bidirectional iterators, like std::list<char>::iterator // std::list<char> lista; // std::copy(str.begin(), str.end(), std::back_inserter(lista)); // reverse_word_order(lista.begin(), lista.end(), // std::ostream_iterator<char>(std::cout, ""), ' '); std::string str1("a b "); std::string str2(" a b"); std::string str3(" "); std::string str4(""); // outputs "words? these Are" std::cout << '"'; reverse_word_order(str.begin(), str.end(), std::ostream_iterator<char>(std::cout, ""), ' '); std::cout << '"' << std::endl << '"'; // outputs " b a" reverse_word_order(str1.begin(), str1.end(), std::ostream_iterator<char>(std::cout, ""), ' '); std::cout << '"' << std::endl << '"'; // outputs "b a " reverse_word_order(str2.begin(), str2.end(), std::ostream_iterator<char>(std::cout, ""), ' '); std::cout << '"' << std::endl << '"'; // outputs " " reverse_word_order(str3.begin(), str3.end(), std::ostream_iterator<char>(std::cout, ""), ' '); std::cout << '"' << std::endl << '"'; // outputs "" reverse_word_order(str4.begin(), str4.end(), std::ostream_iterator<char>(std::cout, ""), ' '); std::cout << '"' << std::endl; return 0; }
If we use the ready made algorithms distance and advance, we don't have to care about tag dispatching: the STL does it for us.
#include <iostream> #include <cstring> template <typename ForwardIter> ForwardIter mid_point(ForwardIter begin, ForwardIter end) { ForwardIter i = begin; std::advance(i, std::distance(begin, end)/2); return i; } int main() { char* array = "123456789"; std::cout << *mid_point(array, array+strlen(array)) << std::endl; return 0; }