From 82a8ea390253df9d83012964af06310992e4c316 Mon Sep 17 00:00:00 2001 From: q66 Date: Sat, 11 Jul 2015 17:26:41 +0100 Subject: [PATCH] SFINAE friendly ToString and expansion of any tuple-like type in format --- octa/format.hh | 46 +++++++++++++++++++++++++++++-------- octa/string.hh | 62 ++++++++++++++++++++++++++++++-------------------- octa/tuple.hh | 4 ++-- 3 files changed, 75 insertions(+), 37 deletions(-) diff --git a/octa/format.hh b/octa/format.hh index f92d4ef..af8661f 100644 --- a/octa/format.hh +++ b/octa/format.hh @@ -14,6 +14,7 @@ #include "octa/algorithm.hh" #include "octa/string.hh" #include "octa/utility.hh" +#include "octa/internal/tuple.hh" namespace octa { @@ -458,21 +459,46 @@ namespace detail { template using FmtRangeTest = decltype(test_fmt_range(0)); + template + struct FmtTupleUnpacker { + template + static inline Ptrdiff unpack(R &writer, Size &fmtn, bool esc, + const char *fmt, const T &item, + const A &...args) { + return FmtTupleUnpacker::unpack(writer, fmtn, esc, fmt, + item, get(item), args...); + } + }; + + template<> + struct FmtTupleUnpacker<0> { + template + static inline Ptrdiff unpack(R &writer, Size &fmtn, bool esc, + const char *fmt, const T &, + const A &...args) { + return format_impl(writer, fmtn, esc, fmt, args...); + } + }; + template inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc, bool, - const char *fmt, const T &item) { + const char *fmt, const T &item, + EnableIf::value, bool> + = true) { return format_impl(writer, fmtn, esc, fmt, item); } - template + template inline Ptrdiff format_ritem(R &writer, Size &fmtn, bool esc, bool expandval, const char *fmt, - const Pair &pair) { + const T &item, + EnableIf::value, bool> + = true) { if (expandval) { - return format_impl(writer, fmtn, esc, fmt, pair.first, - pair.second); + return FmtTupleUnpacker::value>::unpack(writer, + fmtn, esc, fmt, item); } - return format_impl(writer, fmtn, esc, fmt, pair); + return format_impl(writer, fmtn, esc, fmt, item); } template @@ -515,9 +541,8 @@ namespace detail { return -1; } - template())) - > static True test_fmt_tostr(int); + template + static True test_fmt_tostr(decltype(octa::to_string(declval())) *); template static False test_fmt_tostr(...); template @@ -756,7 +781,8 @@ namespace detail { /* generic failure case */ template Ptrdiff write(R &, bool, const T &, EnableIf< - !IsArithmetic::value && !FmtTostrTest::value, bool + !IsArithmetic::value && !FmtTostrTest::value && + !FmtTofmtTest>::value, bool > = true) { assert(false && "value cannot be formatted"); return -1; diff --git a/octa/string.hh b/octa/string.hh index 25cd68b..f278a9d 100644 --- a/octa/string.hh +++ b/octa/string.hh @@ -485,24 +485,24 @@ namespace detail { template static int test(...); static constexpr bool value = (sizeof(test(0)) == sizeof(char)); }; + + template + static True test_iterable(decltype(octa::iter(declval())) *); + template static False test_iterable(...); + + template + using IterableTest = decltype(test_iterable(0)); } -template struct ToString { +template +struct ToString; + +template +struct ToString::value>> { using Argument = T; using Result = String; - template - static String to_str(const U &v, - EnableIf::value, bool> = true - ) { - return v.to_string(); - } - - template - static String to_str(const U &v, - EnableIf::value && - !IsScalar::value, bool> = true - ) { + String operator()(const T &v) const { String ret("{"); ret += concat(octa::iter(v), ", ", ToString< RemoveCv struct ToString { ret += "}"; return ret; } +}; - template - static String to_str(const U &v, - EnableIf::value && - IsScalar::value, bool> = true - ) { - return ToString()(v); - } +template +struct ToString::value>> { + using Argument = T; + using Result = String; String operator()(const T &v) const { - return to_str(v); + return ToString()(v); } }; +template +struct ToString::value>> { + using Argument = T; + using Result = String; + + String operator()(const T &v) const { + return v.to_string(); + } +}; + +template struct ToString::value && + !detail::ToStringTest::value && + !IsScalar::value +>>: ToString {}; + namespace detail { template void str_printf(Vector *s, const char *fmt, T v) { @@ -637,10 +651,8 @@ template struct ToString> { } }; -template struct ToString: ToString {}; - -template()(declval()))> -String to_string(const T &v) { +template +typename ToString::Result to_string(const T &v) { return ToString()(v); } diff --git a/octa/tuple.hh b/octa/tuple.hh index cfcc912..b4e72a9 100644 --- a/octa/tuple.hh +++ b/octa/tuple.hh @@ -277,10 +277,10 @@ class Tuple { friend TupleElement> &get(Tuple &); template - friend TupleElement> &get(const Tuple &); + friend const TupleElement> &get(const Tuple &); template - friend TupleElement> &get(Tuple &&); + friend TupleElement> &&get(Tuple &&); public: template