From 803292dda5bbab07a340a2bfa7460dd7fa071149 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Wed, 27 Jan 2016 12:38:16 +0100 Subject: [PATCH] refactoring: towards a more generic formulation because this element picking mechanism for tuples looks like an instance of something generic. At least I've written almost the same just some days ago for the revised version of function-closure, where the task was to replace a stretch of type arguments in a given tuple type with a stretch of placeholder types and then to build a modified ctor, which just fills in the remaining arguments, while default constructing the placeholder types. And if we look into the GNU implementation of std::bind, they're using a similar concept (with the difference that they're building a functor object, where we use a type converter) This refactoring also integrates some generally useful bits into our standard metaprogramming helper collection --- research/try.cpp | 166 ++++++++------------------------ src/lib/meta/trait.hpp | 88 ++++++++++++++++- src/lib/meta/tuple-helper.hpp | 16 +++ src/lib/meta/typelist-manip.hpp | 4 +- src/lib/meta/typeseq-util.hpp | 12 +++ 5 files changed, 155 insertions(+), 131 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 59eb6397b..818929e1c 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -68,7 +68,9 @@ using lib::diff::GenNode; using lib::diff::DataValues; using lib::meta::Types; using lib::meta::Tuple; +using lib::meta::Pick; using lib::meta::IndexSeq; +using lib::meta::IndexIter; using lib::meta::BuildIndexSeq; using lib::meta::InstantiateChained; using lib::meta::Filter; @@ -80,86 +82,6 @@ using std::tuple; namespace error = lumiera::error; - //////////////////////////////////////TODO traits -namespace lib { -namespace meta { - using std::is_constructible; - using std::is_unsigned; - using std::is_signed; - using std::is_floating_point; - - - template - struct is_nonFloat - : __and_ - ,__not_> - > - { }; - - /** temporary workaround for GCC [Bug-63723], necessary until CGG-5 - * @remarks The problem is that GCC emits a warning on narrowing conversion, - * instead of letting the SFINAE substitution fail. This can be considered - * questionable behaviour, since the usual implementation of a `is_convertible` - * trait uses initialisation from a brace enclosed list, where C++11 prohibits - * narrowing conversions. Now the problem is, that we'll use such traits checks - * to remove such _impossble_ cases from generated trampoline tables or visitor - * double dispatch implementations. Thus, for one we get lots of warnings at that - * point when generating those trampoline tables (at initialisation), while it - * is not clear we'll trigger those cases, and, when we do, we'll get narrowing - * conversions in a context where we're unable to cope with them or protect - * ourselves against spurious conversions. - * What follows is a quick-n-dirty hack to remove such unwanted conversions. - * - * [Bug-63723]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63723 - */ - template - struct is_narrowingInit - : __or_<__and_, is_signed> - ,__and_, is_unsigned> - ,__and_, is_floating_point> - ,__and_, is_nonFloat> - ,__not_> - > - { }; - -#define TRAIT_IS_NARROWING(_SRC_, _TAR_) \ - template<> \ - struct is_narrowingInit<_SRC_, _TAR_> \ - : std::true_type \ - { }; - - TRAIT_IS_NARROWING (int64_t, int32_t) - TRAIT_IS_NARROWING (int64_t, int16_t) - TRAIT_IS_NARROWING (int64_t, int8_t) - TRAIT_IS_NARROWING (int32_t, int16_t) - TRAIT_IS_NARROWING (int32_t, int8_t) - TRAIT_IS_NARROWING (int16_t, int8_t) - TRAIT_IS_NARROWING (int16_t, short) - TRAIT_IS_NARROWING (int16_t, char) - - TRAIT_IS_NARROWING (uint64_t, uint32_t) - TRAIT_IS_NARROWING (uint64_t, uint16_t) - TRAIT_IS_NARROWING (uint64_t, uint8_t) - TRAIT_IS_NARROWING (uint32_t, uint16_t) - TRAIT_IS_NARROWING (uint32_t, uint8_t) - TRAIT_IS_NARROWING (uint16_t, uint8_t) - TRAIT_IS_NARROWING (uint16_t, ushort) - - TRAIT_IS_NARROWING (double, float) - - TRAIT_IS_NARROWING (lib::hash::LuidH, int64_t) - TRAIT_IS_NARROWING (lib::hash::LuidH, int32_t) - TRAIT_IS_NARROWING (lib::hash::LuidH, int16_t) - TRAIT_IS_NARROWING (lib::hash::LuidH, int8_t) - TRAIT_IS_NARROWING (lib::hash::LuidH, char) - TRAIT_IS_NARROWING (lib::hash::LuidH, uint16_t) - TRAIT_IS_NARROWING (lib::hash::LuidH, uint8_t) - TRAIT_IS_NARROWING (lib::hash::LuidH, double) - TRAIT_IS_NARROWING (lib::hash::LuidH, float) - -#undef TRAIT_IS_NARROWING - -}} //////////////////////////////////////TODO traits using std::__not_; using std::__and_; using std::__or_; @@ -175,6 +97,19 @@ template struct GenNodeAccessor : boost::noncopyable { + + template + struct allow_Conversion + : __and_ + ,__not_::TypePlain + ,typename Strip::TypePlain>> + > + { }; + + using SupportedSourceTypes = typename Filter::List; + + + struct ConverterBase : DataCapPredicate { @@ -193,15 +128,6 @@ struct GenNodeAccessor }; }; - template - struct allow_Conversion - : __and_ - ,__not_::TypePlain - ,typename Strip::TypePlain>> - > - { }; - - using SupportedSourceTypes = typename Filter::List; using ConversionBuffer = InstantiateChained< SupportedSourceTypes , Converter @@ -225,23 +151,14 @@ struct GenNodeAccessor } }; -//////////TODO this goes into typeseq-util.hpp -template -struct Pick; - -template -struct Pick, i> - { - using Type = typename lib::meta::Shifted, i>::Head; - }; template -struct ElementMapper; +struct ElementExtractor; template -struct ElementMapper> +struct ElementExtractor> { template using TargetType = typename Pick, i>::Type; @@ -263,47 +180,42 @@ struct ElementMapper> -template -struct IdxIter; -template -struct IdxIter> + + +template< typename TYPES + , template class _ElmMapper_ + , class SEQ + > +struct TupleConstructor; + +template< typename TYPES + , template class _ElmMapper_ + , size_t...idx + > +struct TupleConstructor> + : Tuple { - /////TODO as long as Types is not variadic (#987), we need to strip NullType here (instead of just using sizeof...(TYPES) - enum {SIZ = lib::meta::count::List>::value }; - - using Seq = typename BuildIndexSeq::Ascending; - }; - - - -template -class TupleBuilder; - -template -class TupleBuilder> - : public Tuple - { - template - using PickArg = typename ElementMapper::template Access; - public: template - TupleBuilder (SRC values) - : Tuple (PickArg{values}...) + TupleConstructor (SRC values) + : Tuple (_ElmMapper_, idx>{values}...) { } }; - + + +template +using PickArg = typename ElementExtractor::template Access; template Tuple buildTuple (SRC values) { - using IndexSeq = typename IdxIter::Seq; + using IndexSeq = typename IndexIter::Seq; - return TupleBuilder (values); + return TupleConstructor (values); } diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index 189207a67..2f25bd4eb 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -74,10 +74,14 @@ namespace std { } namespace lib{ template class P; -} + + namespace hash { + class LuidH; +}} +namespace proc { namespace mobject{ template class Placement; -} +}} namespace lib { @@ -87,7 +91,11 @@ namespace meta { using std::remove_pointer; using std::remove_reference; using std::is_convertible; + using std::is_constructible; + using std::is_floating_point; using std::is_arithmetic; + using std::is_unsigned; + using std::is_signed; using std::is_same; using std::__not_; using std::__and_; @@ -309,6 +317,82 @@ namespace meta { + + template + struct is_nonFloat + : __and_ + ,__not_> + > + { }; + + /** temporary workaround for GCC [Bug-63723], necessary until CGG-5 + * @remarks The problem is that GCC emits a warning on narrowing conversion, + * instead of letting the SFINAE substitution fail. This can be considered + * questionable behaviour, since the usual implementation of a `is_convertible` + * trait uses initialisation from a brace enclosed list, where C++11 prohibits + * narrowing conversions. Now the problem is, that we'll use such traits checks + * to remove such _impossble_ cases from generated trampoline tables or visitor + * double dispatch implementations. Thus, for one we get lots of warnings at that + * point when generating those trampoline tables (at initialisation), while it + * is not clear we'll trigger those cases, and, when we do, we'll get narrowing + * conversions in a context where we're unable to cope with them or protect + * ourselves against spurious conversions. + * What follows is a quick-n-dirty hack to remove such unwanted conversions. + * + * [Bug-63723]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63723 + */ + template + struct is_narrowingInit + : __or_<__and_, is_signed> + ,__and_, is_unsigned> + ,__and_, is_floating_point> + ,__and_, is_nonFloat> + ,__not_> + > + { }; + +#define TRAIT_IS_NARROWING(_SRC_, _TAR_) \ + template<> \ + struct is_narrowingInit<_SRC_, _TAR_> \ + : std::true_type \ + { }; + + TRAIT_IS_NARROWING (int64_t, int32_t) + TRAIT_IS_NARROWING (int64_t, int16_t) + TRAIT_IS_NARROWING (int64_t, int8_t) + TRAIT_IS_NARROWING (int32_t, int16_t) + TRAIT_IS_NARROWING (int32_t, int8_t) + TRAIT_IS_NARROWING (int16_t, int8_t) + TRAIT_IS_NARROWING (int16_t, short) + TRAIT_IS_NARROWING (int16_t, char) + + TRAIT_IS_NARROWING (uint64_t, uint32_t) + TRAIT_IS_NARROWING (uint64_t, uint16_t) + TRAIT_IS_NARROWING (uint64_t, uint8_t) + TRAIT_IS_NARROWING (uint32_t, uint16_t) + TRAIT_IS_NARROWING (uint32_t, uint8_t) + TRAIT_IS_NARROWING (uint16_t, uint8_t) + TRAIT_IS_NARROWING (uint16_t, ushort) + + TRAIT_IS_NARROWING (double, float) + + TRAIT_IS_NARROWING (lib::hash::LuidH, int64_t) + TRAIT_IS_NARROWING (lib::hash::LuidH, int32_t) + TRAIT_IS_NARROWING (lib::hash::LuidH, int16_t) + TRAIT_IS_NARROWING (lib::hash::LuidH, int8_t) + TRAIT_IS_NARROWING (lib::hash::LuidH, char) + TRAIT_IS_NARROWING (lib::hash::LuidH, uint16_t) + TRAIT_IS_NARROWING (lib::hash::LuidH, uint8_t) + TRAIT_IS_NARROWING (lib::hash::LuidH, double) + TRAIT_IS_NARROWING (lib::hash::LuidH, float) + +#undef TRAIT_IS_NARROWING + + + + + + /* ====== generic iteration support ====== */ /** Trait template to detect a type usable immediately as diff --git a/src/lib/meta/tuple-helper.hpp b/src/lib/meta/tuple-helper.hpp index db65c34bd..3fc5d47fc 100644 --- a/src/lib/meta/tuple-helper.hpp +++ b/src/lib/meta/tuple-helper.hpp @@ -228,6 +228,22 @@ namespace meta { }; + + /** build an index number sequence from a structured reference type */ + template + struct IndexIter; + + /** build an index number sequence from a type sequence */ + template + struct IndexIter> + { + /////TODO as long as Types is not variadic (#987), we need to strip NullType here (instead of just using sizeof...(TYPES) + enum {SIZ = lib::meta::count::List>::value }; + + using Seq = typename BuildIndexSeq::Ascending; + }; + + diff --git a/src/lib/meta/typelist-manip.hpp b/src/lib/meta/typelist-manip.hpp index 536630e13..b6ab6ca9d 100644 --- a/src/lib/meta/typelist-manip.hpp +++ b/src/lib/meta/typelist-manip.hpp @@ -63,7 +63,7 @@ namespace meta { /** pick the n-th element from a typelist */ - template + template struct Pick { typedef NullType Type; @@ -73,7 +73,7 @@ namespace meta { { typedef TY Type; }; - template + template struct Pick, i> { typedef typename Pick::Type Type; diff --git a/src/lib/meta/typeseq-util.hpp b/src/lib/meta/typeseq-util.hpp index 79c76e878..88f4d9ba1 100644 --- a/src/lib/meta/typeseq-util.hpp +++ b/src/lib/meta/typeseq-util.hpp @@ -201,6 +201,18 @@ namespace meta { + /** + * specialisation: pick n-th element from a type sequence + * @see typelist-manip.hpp + */ + template + struct Pick, i> + { + using Type = typename lib::meta::Shifted, i>::Head; + }; + + + }} // namespace lib::meta