From 7cdac42c4adb98506944842a25c6d35a2f33a2dc Mon Sep 17 00:00:00 2001 From: q66 Date: Mon, 15 Jun 2015 18:54:00 +0100 Subject: [PATCH] sfinae friendly range traits + IsInputRange etc now works on arbitrary non-range types --- octa/range.h | 111 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 22 deletions(-) diff --git a/octa/range.h b/octa/range.h index 0a8813a..191588d 100644 --- a/octa/range.h +++ b/octa/range.h @@ -26,11 +26,19 @@ template struct RangeHalf; #define OCTA_RANGE_TRAIT(Name) \ namespace detail { \ template \ - struct Range##Name##Base { \ + struct Range##Name##Test { \ + template static char test(RemoveReference *); \ + template static int test(...); \ + static constexpr bool value = (sizeof(test(0)) == sizeof(char)); \ + }; \ + template::value> \ + struct Range##Name##Base {}; \ + template \ + struct Range##Name##Base { \ using Type = typename T::Name; \ }; \ template \ - struct Range##Name##Base> { \ + struct Range##Name##Base, true> { \ using Type = typename T::Name; \ }; \ } \ @@ -45,50 +53,109 @@ OCTA_RANGE_TRAIT(Difference) #undef OCTA_RANGE_TRAIT +namespace detail { + template + struct IsRangeTest { + template static char test(typename U::Category *, + typename U::Size *, + typename U::Difference *, + typename U::Value *, + RemoveReference< + typename U::Reference + > *); + template static int test(...); + static constexpr bool value + = (sizeof(test(0, 0, 0, 0, 0)) == sizeof(char)); + }; +} + // is input range -template, InputRangeTag ->::value> struct IsInputRange: False {}; +namespace detail { + template, InputRangeTag + >::value> struct IsInputRangeBase: False {}; + + template + struct IsInputRangeBase: True {}; +} + +template::value> +struct IsInputRange: False {}; template -struct IsInputRange: True {}; +struct IsInputRange: octa::detail::IsInputRangeBase::Type {}; // is forward range -template, ForwardRangeTag ->::value> struct IsForwardRange: False {}; +namespace detail { + template, ForwardRangeTag + >::value> struct IsForwardRangeBase: False {}; + + template + struct IsForwardRangeBase: True {}; +} + +template::value> +struct IsForwardRange: False {}; template -struct IsForwardRange: True {}; +struct IsForwardRange: octa::detail::IsForwardRangeBase::Type {}; // is bidirectional range -template, BidirectionalRangeTag ->::value> struct IsBidirectionalRange: False {}; +namespace detail { + template, BidirectionalRangeTag + >::value> struct IsBidirectionalRangeBase: False {}; + + template + struct IsBidirectionalRangeBase: True {}; +} + +template::value> +struct IsBidirectionalRange: False {}; template -struct IsBidirectionalRange: True {}; +struct IsBidirectionalRange: + octa::detail::IsBidirectionalRangeBase::Type {}; // is random access range -template, RandomAccessRangeTag ->::value> struct IsRandomAccessRange: False {}; +namespace detail { + template, RandomAccessRangeTag + >::value> struct IsRandomAccessRangeBase: False {}; + + template + struct IsRandomAccessRangeBase: True {}; +} + +template::value> +struct IsRandomAccessRange: False {}; template -struct IsRandomAccessRange: True {}; +struct IsRandomAccessRange: + octa::detail::IsRandomAccessRangeBase::Type {}; // is finite random access range -template, FiniteRandomAccessRangeTag ->::value> struct IsFiniteRandomAccessRange: False {}; +namespace detail { + template, FiniteRandomAccessRangeTag + >::value> struct IsFiniteRandomAccessRangeBase: False {}; + + template + struct IsFiniteRandomAccessRangeBase: True {}; +} + +template::value> +struct IsFiniteRandomAccessRange: False {}; template -struct IsFiniteRandomAccessRange: True {}; +struct IsFiniteRandomAccessRange: + octa::detail::IsFiniteRandomAccessRangeBase::Type {}; // is infinite random access range