#ifndef CONCATENATE_H #define CONCATENATE_H #include #include template class ConcatenatedIterator { public: using value_type = typename IT1::value_type; using reference = typename IT1::reference; friend void swap(ConcatenatedIterator& lhs, ConcatenatedIterator& rhs) { using std::swap; swap(lhs.is_end, rhs.is_end); swap(lhs.begin1, rhs.begin1); swap(lhs.end1, rhs.end1); swap(lhs.begin2, rhs.begin2); swap(lhs.end2, rhs.end2); } ConcatenatedIterator() : is_end(true) { } ConcatenatedIterator(IT1 begin1, IT1 end1, IT2 begin2, IT2 end2) : is_end(false), begin1(begin1), end1(end1), begin2(begin2), end2(end2) { } ConcatenatedIterator(const ConcatenatedIterator& other) : is_end(other.is_end), begin1(other.begin1), end1(other.end1), begin2(other.begin2), end2(other.end2) { } ConcatenatedIterator(ConcatenatedIterator&& other) : ConcatenatedIterator() { swap(*this, other); } ConcatenatedIterator& operator=(ConcatenatedIterator other) { swap(*this, other); return *this; } reference operator*() const { if (begin1 != end1) { return *begin1; } else { return *begin2; } } ConcatenatedIterator& operator++() { if (!is_end) { if (begin1 != end1) { ++begin1; } else if (begin2 != end2) { ++begin2; } if (begin1 == end1 && begin2 == end2) is_end = true; } return *this; } bool operator==(const ConcatenatedIterator& other) const { if (is_end && other.is_end) return true; if (is_end != other.is_end) return false; if (begin1 != end1 && other.begin1 != other.end1) { return begin1 == other.begin1; } if (begin1 != end1 || other.begin1 != other.end1) return false; if (begin2 != end2 && other.begin2 != other.end2) { return begin2 == other.begin2; } return false; } bool operator!=(const ConcatenatedIterator& other) const { return !(*this == other); } private: bool is_end; IT1 begin1; IT1 end1; IT2 begin2; IT2 end2; }; template class ConcatenatedContainerView { public: using iterator = ConcatenatedIterator< typename C1::const_iterator, typename C2::const_iterator>; using const_iterator = iterator; using value_type = typename C1::value_type; ConcatenatedContainerView(const C1& c1, const C2& c2) : it(c1.begin(), c1.end(), c2.begin(), c2.end()) { } iterator begin() const { return it; } iterator end() const { return iterator(); } private: const iterator it; }; template using ConcatenationResult = typename std::enable_if< // check that both containers have the same element type std::is_same< decltype(*std::declval().begin()), decltype(*std::declval().begin()) >::value, // check that C1 and C2 support iterators typename std::remove_reference< decltype( std::declval().begin(), std::declval().end(), std::declval().begin(), std::declval().end(), std::declval>() ) >::type >::type; template ConcatenationResult concatenate(const C1& c1, const C2& c2) { return ConcatenatedContainerView(c1, c2); } template ConcatenationResult operator&(const C1& c1, const C2& c2) { return concatenate(c1, c2); } #endif