Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pretty print for all classes with ranged-base for loop support

Tags:

c++

I want to implement pretty-print for all classes with ranged-base for loop support by overloadding <<. The (wrong) code is like this.

template<class C> ostream& operator<<(ostream& out, const C& v) {
  for(auto x : v) out<<x<<' ';
  return out;
}

The problem here is that this will conflict with existing << overloading. Is there a way to specify in the template that C must support ranged-base for loop?

like image 945
Chaoxu Tong Avatar asked Oct 26 '13 16:10

Chaoxu Tong


1 Answers

Since range-based for loops require begin(v) and end(v) to be valid with ADL (and std:: being an associated namespace), you can use this:

namespace support_begin_end
{
    // we use a special namespace (above) to
    // contain the using directive for 'std':
    using namespace std;

    // the second parameter is only valid
    // when begin(C()) and end(C()) are valid
    template<typename C,
        typename=decltype(begin(std::declval<C>()),end(std::declval<C>()))
    >
    struct impl
    {
        using type = void; // only here impl
    };

    // explicitly disable conflicting types here
    template<>
    struct impl<std::string>;
}

// this uses the above to check for ::type,
// which only exists if begin/end are valid
// and there is no specialization to disable it
// (like in the std::string case)
template<class C,typename = typename supports_begin_end::impl<C>::type>
std::ostream& operator<<(std::ostream& out, const C& v) {
    for(auto x : v) out<<x<<' ';
    return out;
}

Live example

There are other types that are suitable for range-based loops, though. Don't know if you need to detect them as well.


Here's an updated live example which detects both containers/types that support begin(v)/end(v) as well as types that support v.begin()/v.end().

like image 72
Daniel Frey Avatar answered Sep 28 '22 20:09

Daniel Frey