#include #include #include #include #include void dummy(); template void pretty_print(std::ostream& os, T const& value); namespace impl { template void pretty_print(std::ostream& os, T const& value) requires requires { *value; } { os << "*("; ::pretty_print(os, *value); os << ")"; } template void pretty_print(std::ostream& os, T const& value) requires (requires { os << value; } and not requires { *value; }) { os << value; } template void pretty_print(std::ostream& os, T const& value) requires (requires { value[0]; value.size(); } and not requires { os << value; } and not requires { *value; }) { os << "{"; for (std::size_t i { 0 }; i < value.size(); ++i) { os << " "; ::pretty_print(os, value[i]); } os << " }"; } } template void pretty_print(std::ostream& os, T const& value) { impl::pretty_print(os, value); } int main() { // test simple int { std::ostringstream oss { }; pretty_print(oss, 5); assert(( oss.str() == "5" )); } { std::ostringstream oss { }; pretty_print(oss, 3.7); assert(( oss.str() == "3.7" )); } { std::ostringstream oss { }; int x { 17 }; pretty_print(oss, &x); assert(( oss.str() == "*(17)" )); } { std::ostringstream oss { }; std::string str { "hello" }; pretty_print(oss, str); assert(( oss.str() == "hello" )); } std::vector v { "abc", "defg", "hi", "j", "" }; { std::ostringstream oss { }; pretty_print(oss, v); assert(( oss.str() == "{ abc defg hi j }" )); } { std::vector> ptrs { { &v[0], &v[0] }, { &v[1], &v[2], &v[3] }, { } }; std::ostringstream oss { }; pretty_print(oss, ptrs); assert(( oss.str() == "{ { *(abc) *(abc) } { *(defg) *(hi) *(j) } { } }" )); } }