#include <iostream>
#include <cstdlib>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;

template <class RANDOM, class OUTPUT>
OUTPUT __my_copy(RANDOM first, RANDOM last, OUTPUT result,
	random_access_iterator_tag)
{
	cout << "random access iterators\n";
	typedef typename iterator_traits<RANDOM>::difference_type
		difference_type;

	for (difference_type i = last - first; i > 0; --i) {
		*result = *first;
		++first;
		++result;
	}

	return result;
}

template <class INPUT, class OUTPUT>
OUTPUT __my_copy(INPUT first, INPUT last, OUTPUT result,
	input_iterator_tag)
{
	cout << "input iterators that are not random access\n";

	for (; first != last; ++first, ++result) {
		*result = *first;
	}

	return result;
}

template <class INPUT, class OUTPUT>
inline OUTPUT my_copy(INPUT first, INPUT last, OUTPUT result)
{
	typedef typename iterator_traits<INPUT>::iterator_category
		iterator_category;

	return __my_copy(first, last, result, iterator_category());
}

int main()
{
	const int a[] = {10, 20, 30};
	const size_t n = sizeof a / sizeof a[0];

	//First two arguments of my_copy are random access iterators.
	my_copy(a, a + n, ostream_iterator<int>(cout, "\n"));
	cout << "\n";

	//1st 2 args of my_copy are input iterators that are not random access.
	list<int> li(a, a + n);
	my_copy(li.begin(), li.end(), ostream_iterator<int>(cout, "\n"));

	return EXIT_SUCCESS;
}