   printing arrays, vectors, sets and other containers
std::vector<int> numbers;numbers.push_back(4);numbers.push_back(8);numbers.push_back(15);numbers.push_back(16);numbers.push_back(23);numbers.push_back(42);std::cout << numbers << std::endl; // error: no match for operator<<How many times have you wished to be able to print containers? I got sick of counting, so I developed a solution.#include <boost/type_traits.hpp>#include <boost/utility/enable_if.hpp>#include <iosfwd>template<class Iterator> inlinevoid print_sequence(std::ostream& os, Iterator begin, Iterator end){    os << '{';    if (begin != end)    {   os << *begin;   while (++begin != end)   {  os << ", " << *begin;   }    }    os << '}';}template<class Element, size_t size> typenameboost::disable_if<    boost::is_same<typename   boost::remove_cv<Element>::type,   char>,    std::ostream&>::typeoperator<<(std::ostream& os, Element (&array)[size]){    print_sequence(os, array, array + size);    return os;}template<class T>struct has_begin_end{    template<class U, typename U::const_iterator (U::*)() const,  typename U::const_iterator (U::*)() const> struct sfinae{};    template<class U> static char test(sfinae<U, &U::begin, &U::end>*);    template<class U> static long test(...);    enum { value = 1 == sizeof test<T>(0) };    typedef boost::integral_constant<bool, value> type;};template<class Sequence> typenameboost::enable_if<    has_begin_end<Sequence>,    std::ostream&>::typeoperator<<(std::ostream& os, const Sequence& sequence){    print_sequence(os, sequence.begin(), sequence.end());    return os;}This works with arbitrarily nested containers. Let me know what you think.   
  Do you really have to disable_if for character arrays? Won't the char* overload in the standard library be a better match than the T(&)[N] partial specialization (I think this is a partial specialization)?Also, instead of using SFINAE to look for .begin() and .end() members, couldn't you do something with iterator_traits?   ;  Have you tried it with std::string / containers of std::string? It has begin() and end() but it is also a template and already has operator<< overloaded.It is a nice thing to have, of course.Quote:Do you really have to disable_if for character arrays? Won't the char* overload in the standard library be a better match than the T(&)[N] partial specialization (I think this is a partial specialization)?I believe the type of string literals is char[N], so it is indeed needed. (As these are functions, it's not a partial specialization.)   ;Quote:Original post by visitorHave you tried it with std::string / containers of std::string? It has begin() and end() but it is also a template and already has operator<< overloaded.I tried it out and indeed, operator<< was ambiguous whenever std::string was involved.Also, it didn't compile with std::map or std::set for some odd reason.  Nothing fancy, just your basic example:std::map<int,int> foo;foo[0] = 1;std::cout << foo;I did some investigating, and if we try to compile this:typedef std::map<int,int> MapT;has_begin_end<MapT>::sfinae<MapT, &MapT::begin, &MapT::end> foo;We get:error C2440: 'specialization' : cannot convert from 'overloaded-function' to 'std::_Tree<_Traits>::const_iterator (__thiscall std::map<_Kty,_Ty>::* )(void) const'Which is where our substitution error comes from.  What's interesting is that the following compiles fine:typedef std::map<int,int> MapT;typedef MapT::const_iterator (MapT::*Ptr)() const;Ptr foo = &MapT::begin;Ptr bar = &MapT::end;So it appears to perform the conversion here without problems?  Maybe I'm missing something...EDIT:  This was with Visual C++ 2008 Express.EDIT2:  Even further investigation reveals that it might be a MSVC compiler bug.   ;Quote:Original post by visitorHave you tried it with std::string / containers of std::string? It has begin() and end() but it is also a template and already has operator<< overloaded.I can't believe I haven't tested strings :) Here is a workaround for strings, but of course it would be much nicer to say "disable this for any type that already has operator<<". Something like an operator does_compile(expression) would be cool to have :)#include <iosfwd>#include <boost/mpl/logical.hpp>#include <boost/type_traits.hpp>#include <boost/utility/enable_if.hpp>template<class Iterator>void print_sequence(std::ostream& os, Iterator begin, Iterator end){    os << '{';    const char* delimiter = "";    for (Iterator it = begin; it != end; ++it)    {   os << delimiter << *it;   delimiter = ", ";    }    os << '}';}template<class Element, size_t size>typename boost::disable_if<    boost::is_same<   typename boost::remove_cv<Element>::type,   char    >,    std::ostream&>::typeoperator<<(std::ostream& os, Element (&array)[size]){    print_sequence(os, array, array + size);    return os;}template<class T>struct has_begin_end{    template<class U, typename U::const_iterator (U::*)() const,  typename U::const_iterator (U::*)() const> struct sfinae{};    template<class U> static char test(sfinae<U, &U::begin, &U::end>*);    template<class U> static long test(...);    enum { value = 1 == sizeof test<T>(0) };    typedef boost::integral_constant<bool, value> type;};template<class Sequence>typename boost::enable_if<    boost::mpl::and_<   has_begin_end<Sequence>,   boost::mpl::not_<  boost::is_same< typename boost::remove_cv<Sequence>::type, std::string  >   >    >,    std::ostream&>::typeoperator<<(std::ostream& os, const Sequence& sequence){    print_sequence(os, sequence.begin(), sequence.end());    return os;};Quote:Original post by DevFredI can't believe I haven't tested strings :) Here is a workaround for strings, but of course it would be much nicer to say "disable this for any type that already has operator<<". Something like an operator does_compile(expression) would be cool to have :)*** Source Snippet Removed ***How about this:// completely untested!template<typename Range>class printable_range{    printable_range(Range &r) : r(&r) { }    Range *r;};template<typename Range>printable_range<Range> seq(Range &r){   return printable_range<Range>(r);}template<typename Range>std::ostream &operator<< (std::ostream &out, const printable_range<Range> &pr){    // custom meta-goo}// ...std::vector<int> v;fill_with_stuff(v);std::cout << seq(v) << '\n';Then you don't have to add the crazy operator<< overload or need a special case for strings: you can stream strings normally, or use seq() to "explode" them.EDIT: just a thought. If you were to format sequences that held std::pair<>s like this: { "a": 1, "b": 2 }, you'd be converging on a pretty tidy JSON exporter...   ;Quote:Then you don't have to add the crazy operator<< overload or need a special case for strings: you can stream strings normally, or use seq() to "explode" them.But then it won't be recursive. If you want to make it recursive, you'll face all the same problems (how will you handle vector<vector<int> >? what about vector<string>?)   ;Quote:Original post by visitorQuote:Then you don't have to add the crazy operator<< overload or need a special case for strings: you can stream strings normally, or use seq() to "explode" them.But then it won't be recursive. If you want to make it recursive, you'll face all the same problems (how will you handle vector<vector<int> >? what about vector<string>?)The recursive stuff still happens at the point where I commented "custom meta-goo".   ;Quote:Original post by DevFredSomething like an operator does_compile(expression) would be cool to have :)It can be done with sizeof(expression). Here is a refined solution which is easier to read and adapt than what I had posted earlier (now deleted):template<class T> T& lvalue_of_type();template<class T> T  rvalue_of_type();template<class T>struct is_already_printable{    template<class U> static char test(char(*)[sizeof(   lvalue_of_type<std::ostream>() << rvalue_of_type<U>()    )]);    template<class U> static long test(...);    enum { value = 1 == sizeof test<T>(0) };    typedef boost::integral_constant<bool, value> type;};template<class Iterable>typename boost::enable_if<    boost::mpl::and_<   is_iterable<Iterable>,   boost::mpl::not_<is_already_printable<Iterable> >    >,    std::ostream&>::typeoperator<<(std::ostream& os, const Iterable& iterable){    print_elements(os, iterable.begin(), iterable.end());    return os;} [Edited by - DevFred on January 24, 2010 11:50:59 AM];Quote:Original post by DevFredQuote:Original post by DevFredSomething like an operator does_compile(expression) would be cool to have :)It can be done with sizeof(expression). Here is a refined solution which is easier to read and adapt than what I had posted earlier (now deleted):*** Source Snippet Removed ***Let me check I'm understand this...If the expression "lvalue_of_type<std::ostream>() << rvalue_of_type<U>()" is illegal, then the first overload of is_already_printable::test() is excluded.Does SFINAE really allow this?I tried this code:#include <ostream>#include <iostream>#include <string>template<typename T> T &lv();template<typename T> T rv();template<typename T>struct streamable{    typedef char small;    typedef char (&big)[2];    template<typename U>    static small test( char (*)[sizeof( lv<std::ostream>() << rv<U>() )] );    template<typename U>    static big test(...);    static const bool value = (sizeof test<T>(0) == sizeof(small));};class X { };int main(){    std::cout << streamable<X>::value << '\n';    std::cout << streamable<std::string>::value << '\n';    std::cout << streamable<int>::value << '\n';    return 0;}It compiled under g++ 4.4 and Visual C++ 2008, but each gave a different output: 0,1,1 and 1,1,1 respectively. I can't make sense of Visual C++'s output, though!   