diff options
author | Håvard Pettersen <havardpe@oath.com> | 2020-06-13 15:08:51 +0000 |
---|---|---|
committer | Håvard Pettersen <havardpe@oath.com> | 2020-06-13 15:08:51 +0000 |
commit | c9c54cbc1f20ed5f54bc63035fe7881604c795ff (patch) | |
tree | feccbfb366083d0b9558faa4b898b61d8eb61cad | |
parent | 24a8b542e20c8758f2d5973fc21e979b80247dae (diff) |
auto-detect actual type typify results
-rw-r--r-- | eval/src/vespa/eval/eval/aggr.h | 6 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/util/typify.h | 40 |
2 files changed, 30 insertions, 16 deletions
diff --git a/eval/src/vespa/eval/eval/aggr.h b/eval/src/vespa/eval/eval/aggr.h index e7431c2c23b..169f0b1d2af 100644 --- a/eval/src/vespa/eval/eval/aggr.h +++ b/eval/src/vespa/eval/eval/aggr.h @@ -2,6 +2,7 @@ #pragma once +#include <vespa/vespalib/util/typify.h> #include <vespa/vespalib/stllike/string.h> #include <vector> #include <map> @@ -120,10 +121,7 @@ public: } // namespave vespalib::eval::aggr struct TypifyAggr { - template <template<typename> typename A> struct Result { - static constexpr bool is_type = false; - template <typename T> using templ = A<T>; - }; + template <template<typename> typename TT> using Result = TypifyResultSimpleTemplate<TT>; template <typename F> static decltype(auto) resolve(Aggr aggr, F &&f) { switch (aggr) { case Aggr::AVG: return f(Result<aggr::Avg>()); diff --git a/vespalib/src/vespa/vespalib/util/typify.h b/vespalib/src/vespa/vespalib/util/typify.h index a2a24baca41..afedb4219a5 100644 --- a/vespalib/src/vespa/vespalib/util/typify.h +++ b/vespalib/src/vespa/vespalib/util/typify.h @@ -10,27 +10,40 @@ namespace vespalib { //----------------------------------------------------------------------------- /** - * Typification result for values resolving into actual types. + * Typification result for values resolving into actual types. Using + * this exact template is not required, but the result type must have + * the name 'type' for the auto-unwrapping performed by typify_invoke + * to work. **/ template <typename T> struct TypifyResultType { - static constexpr bool is_type = true; using type = T; }; /** - * Typification result for values resolving into compile-time values - * which are also types as long as they are kept inside their result - * wrappers. + * Typification result for values resolving into non-types. Using this + * exact template is not required, but is supplied for + * convenience. The resolved compile-time value should be called + * 'value' for consistency across typifiers. **/ template <typename T, T VALUE> struct TypifyResultValue { - static constexpr bool is_type = false; static constexpr T value = VALUE; }; /** + * Typification result for values resolving into simple templates + * (templated on one type). Using this exact template is not required, + * but is supplied as convenience and example. The resolved template + * should be called 'templ' for consistency across typifiers. + **/ +template <template<typename> typename TT> struct TypifyResultSimpleTemplate { + template <typename T> using templ = TT<T>; +}; + +/** * A Typifier is able to take a run-time value and resolve it into a - * type. The resolve result is passed to the specified function in the - * form of a thin result wrapper. + * type, non-type constant value or a template. The resolve result is + * passed to the specified function in the form of a thin result + * wrapper. **/ struct TypifyBool { template <bool VALUE> using Result = TypifyResultValue<bool, VALUE>; @@ -58,6 +71,8 @@ template <size_t N, typename Typifier, typename Target, typename ...Rs> struct T static_assert(sizeof...(Rs) == N); return Target::template invoke<Rs...>(); } + template <class, class = std::void_t<>> struct has_type : std::false_type {}; + template <class T> struct has_type<T, std::void_t<typename T::type>> : std::true_type {}; template <typename T, typename ...Args> static decltype(auto) select(T &&value, Args &&...args) { if constexpr (N == sizeof...(Rs)) { return Target::template invoke<Rs...>(std::forward<T>(value), std::forward<Args>(args)...); @@ -65,7 +80,8 @@ template <size_t N, typename Typifier, typename Target, typename ...Rs> struct T return Typifier::resolve(value, [&](auto t)->decltype(auto) { using X = decltype(t); - if constexpr (X::is_type) { + constexpr bool x_has_type = has_type<X>::value; + if constexpr (x_has_type) { return TypifyInvokeImpl<N, Typifier, Target, Rs..., typename X::type>::select(std::forward<Args>(args)...); } else { return TypifyInvokeImpl<N, Typifier, Target, Rs..., X>::select(std::forward<Args>(args)...); @@ -82,9 +98,9 @@ template <size_t N, typename Typifier, typename Target, typename ...Rs> struct T * the typification results from the N first parameters as template * parameters. Note that typification results that are types are * unwrapped before being used as template parameters while - * typification results that are compile-time values are kept in their - * wrappers when passed as template parameters. Please refer to the - * unit test for examples. + * typification results that are non-types or templates are kept in + * their wrappers when passed as template parameters. Please refer to + * the unit test for examples. **/ template <size_t N, typename Typifier, typename Target, typename ...Args> decltype(auto) typify_invoke(Args && ...args) { static_assert(N > 0); |