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 {
};
/* implementing formatting for custom objects - external function */
template<typename R>
void to_format(Foo const &, R &writer, format_spec const &fs) {
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 */
/* implementing formatting for custom objects */
template<>
struct format_traits<Foo> {
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()) {
case 'i':
range_put_all(writer, "Bar1"_sr);
range_put_all(writer, "Foo1"_sr);
break;
default:
range_put_all(writer, "Bar2"_sr);
range_put_all(writer, "Foo2"_sr);
break;
}
}
@ -116,10 +104,6 @@ int main() {
writefln("%s", 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
* 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;
template<
typename T, typename R, typename = std::enable_if_t<std::is_same_v<
decltype(std::declval<T const &>().to_format(
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);
}
/* empty by default, SFINAE friendly */
template<typename>
struct format_traits {};
/* implementation helpers */
namespace detail {
@ -174,9 +167,9 @@ namespace detail {
template<typename T>
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>
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<format_spec const &>()
)) *);
@ -660,7 +653,7 @@ private:
void write_val(R &writer, bool escape, T const &val) const {
/* stuff fhat can be custom-formatted goes first */
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;
}
/* second best, we can convert to string slice */