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?
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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With