forked from OctaForge/libostd
custom formatting is now done with format_traits
Allows definition for any type, even in any foreign namespace.
This commit is contained in:
parent
e714e5f3fb
commit
bd5aa4795c
|
@ -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)
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue