    #include <iterator>
    #include <type_traits>
    #include <iostream>
    #include <vector>
    #include <list>

    template<typename T>
    typename
    std::enable_if<
        std::is_same<
            typename T::iterator_category,
            std::bidirectional_iterator_tag
        >::value,
        T
    >::type
    foo(T it)
    {
        std::cout << "bidirectional\n";
        return it;
    }
    
    template<typename T>
    typename
    std::enable_if<
        std::is_same<
            typename T::iterator_category,
            std::random_access_iterator_tag
        >::value,
        T
    >::type
    foo(T it)
    {
        std::cout << "random access\n";
        return it;
    }
    
    template<typename T>
    T* foo(T* it)
    {
        std::cout << "pointer\n";
        return it;
    }
    
    int main()
    {
        std::list<int>::iterator it1;
        std::vector<int>::iterator it2;
        int* it3;
        std::istream_iterator<int> it4;
        foo(it1);
        foo(it2);
        foo(it3);
        //foo(it4); // this one doesn't compile
    }

