#include #include #include #include #include void dummy(); template void pretty_print(std::ostream& os, T const& value); namespace impl { template concept dereferenceable = requires(T value) { *value; }; template concept printable = requires(std::ostream& os, T value) { os << value; }; template concept indexable = requires(T value, std::size_t i) { value[i]; value.size(); }; template void pretty_print(std::ostream& os, T const& value) { os << "*("; ::pretty_print(os, *value); os << ")"; } template void pretty_print(std::ostream& os, T const& value) requires (not dereferenceable) { os << value; } template void pretty_print(std::ostream& os, T const& value) requires (not dereferenceable and not printable) { 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) } { } }" )); } }