custom formatting is now done with format_traits

Allows definition for any type, even in any foreign namespace.
master
Daniel Kolesa 2017-02-25 19:17:08 +01:00
parent e714e5f3fb
commit bd5aa4795c
2 changed files with 12 additions and 35 deletions

View File

@ -12,29 +12,17 @@ using namespace ostd::string_literals;
struct Foo { struct Foo {
}; };
/* implementing formatting for custom objects - external function */ /* implementing formatting for custom objects */
template<typename R> template<>
void to_format(Foo const &, R &writer, format_spec const &fs) { struct format_traits<Foo> {
switch (fs.spec()) {
case 'i':
range_put_all(writer, "Foo1"_sr);
break;
default:
range_put_all(writer, "Foo2"_sr);
break;
}
}
struct Bar {
/* implementing formatting for custom objects - method */
template<typename R> template<typename R>
void to_format(R &writer, format_spec const &fs) const { static void to_format(Foo const &, R &writer, format_spec const &fs) {
switch (fs.spec()) { switch (fs.spec()) {
case 'i': case 'i':
range_put_all(writer, "Bar1"_sr); range_put_all(writer, "Foo1"_sr);
break; break;
default: default:
range_put_all(writer, "Bar2"_sr); range_put_all(writer, "Foo2"_sr);
break; break;
} }
} }
@ -116,10 +104,6 @@ int main() {
writefln("%s", Foo{}); writefln("%s", Foo{});
writefln("%i", Foo{}); writefln("%i", Foo{});
/* again, but using a method for formatting */
writefln("%s", Bar{});
writefln("%i", Bar{});
/* formatting into a string sink (can be any output range, but /* formatting into a string sink (can be any output range, but
* appender makes sure the capacity is unlimited so it's safe) * appender makes sure the capacity is unlimited so it's safe)
*/ */

View File

@ -36,16 +36,9 @@ struct format_error: std::runtime_error {
struct format_spec; struct format_spec;
template< /* empty by default, SFINAE friendly */
typename T, typename R, typename = std::enable_if_t<std::is_same_v< template<typename>
decltype(std::declval<T const &>().to_format( struct format_traits {};
std::declval<R &>(), std::declval<format_spec const &>()
)), void
>>
>
inline void to_format(T const &v, R &writer, format_spec const &fs) {
v.to_format(writer, fs);
}
/* implementation helpers */ /* implementation helpers */
namespace detail { namespace detail {
@ -174,9 +167,9 @@ namespace detail {
template<typename T> template<typename T>
constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value; constexpr bool is_tuple_like = decltype(tuple_like_test<T>(0))::value;
/* test whether to_format works */ /* test if format traits are available for the type */
template<typename T, typename R> template<typename T, typename R>
static std::true_type test_tofmt(decltype(to_format( static std::true_type test_tofmt(decltype(format_traits<T>::to_format(
std::declval<T const &>(), std::declval<R &>(), std::declval<T const &>(), std::declval<R &>(),
std::declval<format_spec const &>() std::declval<format_spec const &>()
)) *); )) *);
@ -660,7 +653,7 @@ private:
void write_val(R &writer, bool escape, T const &val) const { void write_val(R &writer, bool escape, T const &val) const {
/* stuff fhat can be custom-formatted goes first */ /* stuff fhat can be custom-formatted goes first */
if constexpr(detail::fmt_tofmt_test<T, noop_output_range<char>>) { if constexpr(detail::fmt_tofmt_test<T, noop_output_range<char>>) {
to_format(val, writer, *this); format_traits<T>::to_format(val, writer, *this);
return; return;
} }
/* second best, we can convert to string slice */ /* second best, we can convert to string slice */