#include <iostream>
#include <type_traits>
#include <vector>
#include <iostream>
#include <set>

template<typename T, typename Iterator, typename=void>
struct is_iterator_of_type: std::false_type {};

template<typename T, typename Iterator>
struct is_iterator_of_type<
    T,
	Iterator,
	typename std::enable_if<
		std::is_same<
			T,
			typename std::iterator_traits< Iterator >::value_type
		>::value
	>::type
>: std::true_type {};

void test1() {
  std::cout << is_iterator_of_type<int, std::vector<int>::iterator>::value << "\n";
}
template<typename T, typename Container>
auto foo(Container const&) -> typename std::enable_if< is_iterator_of_type<T, typename Container::iterator>::value >::type
{
	std::cout << "Container of int\n";
}
template<typename T>
void foo(...)
{
	std::cout << "No match\n";
}
void test2() {
  std::vector<int> test;
	foo<int>(test);
	foo<int>(test.begin());
	foo<int>(std::set<int>());
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
	typename std::enable_if< is_iterator_of_type<int, typename Container::iterator>::value, std::ostream& >::type
{
	stream << "int container\n";
}
void test3() {
	std::vector<int> test;
	std::cout << test;
	std::set<int> bar;
	std::cout << bar;
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
	typename std::enable_if< is_iterator_of_type<double, typename Container::iterator>::value, std::ostream& >::type
{
	stream << "double container\n";
}
void test4() {
	std::vector<int> test;
	std::cout << test;
	std::set<int> bar;
	std::cout << bar;
	std::vector<double> dtest;
	std::cout << dtest;
}
void test5() {
	std::vector<bool> test;
	// does not compile (naturall):
	// std::cout << test;
}
template<typename Container>
auto operator<<( std::ostream& stream, Container const& c ) ->
	typename std::enable_if< is_iterator_of_type<bool, typename Container::iterator>::value, std::ostream& >::type
{
	stream << "bool container\n";
}
void test6() {
	std::vector<bool> test;
	// now compiles:
	std::cout << test;
}
int main() {
	test1();
	test2();
	test3();
	test4();
	test5();
	test6();
}

