I have been successfully using cxx-prettyprint: A C++ Container Pretty-Printer to log container values. (See also Pretty-print C++ STL containers) It's working like a charm even on the old VS-2005 (VC8) compiler (with the prettyprint98.hpp header), also works well on VS2017-2019 when using it e.g. to make container values printable in Unit Tests.
While studying its interoperability with Boost.Format, I found to my surprise that it simply works out of the box, when other questions suggest it shouldn't because ADL should fail for a user provided output operator.
Looking into the cxx-pp header I found that it simply works because the library does define its output operator(s) inside the std
namespace:
// Main magic entry point: An overload snuck into namespace std.
// Can we do better?
namespace std
{
// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename enable_if< ::pretty_print::is_container<T>::value,
basic_ostream<TChar, TCharTraits> &>::type
operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
}
....
Obviously the authors were not 100% confident with this: qq "Can we do better?"
Adding something to the std
namespace is formally UB:
[C++11: 17.6.4.2.1/1]:
The behavior of a C++ program is undefined if it adds declarations or definitions to namespacestd
or to a namespace within namespacestd
unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
So, is this in cxx-pp formally UB, or is it a template specialization (It doesn't seem like one to me).
Comments as to the practical impact of this, iff UB, would be very welcome.