How to print generic std::list iterator?

You can constrain the type as iterator or const_iterator of std::list. E.g.

template<typename It>
std::enable_if_t<std::is_same_v<It, typename std::list<typename std::iterator_traits<It>::value_type>::iterator> ||
                 std::is_same_v<It, typename std::list<typename std::iterator_traits<It>::value_type>::const_iterator>
                 , std::ostream &> 
operator<<(std::ostream &os, const It &x) {
    return os << "&" << *x;
}

You can SFINAE the const char* out from the operator<< overload.

#include <type_traits> // std::enable_if_t, std::is_same_v, std::remove_reference_t

template<
    typename It,
    typename = typename std::iterator_traits<It>::value_type
>
auto operator<<(std::ostream &os, const It &x)
-> std::enable_if_t< !std::is_same_v<std::remove_reference_t<It>, const char*>, std::ostream&>
{
    return os << "&" << *x;
}

(See a Demo)

Note that, the above is not only restricted for std::list::iterator, meaning the iterators from the other containers, can also consider this overload. This might not be the behaviour you want.


Since we could not get the container type from the iterator, I would suggest the same as @super mentioned in the comments. Provide a operator<< overload for the Legacy Bidirectional Iterator which is what the std::list has.

Following is an example code, which will work for your expected cases as well as all the containers, which meet the requirements of a bidirectional iterator.

#include <list>
#include <iostream>
#include <iterator>    // std::iterator_traits, std::bidirectional_iterator_tag
#include <type_traits> // std::is_same_v, std::enable_if_t

// SFINAE helper  type for bidirectional_iterator_t
template<typename Iterator, typename ReType = void>
using enable_for_bidirectional_iterator_t
= std::enable_if_t<
   std::is_same_v<std::bidirectional_iterator_tag, typename std::iterator_traits<Iterator>::iterator_category>
   , ReType
>;

template<typename Iterator>
auto operator<<(std::ostream& os, const Iterator x) noexcept
-> enable_for_bidirectional_iterator_t<Iterator, std::ostream&>
{
   return os << "&" << *x;
}

(See a Demo)


However, usually, you provide an operator<< overload for the container, not for the iterators. You might want to rethink about the design.