Browse Source

meta: minor changes to invoke

doc
Christos Houtouridis 5 years ago
parent
commit
bb35115359
1 changed files with 121 additions and 55 deletions
  1. +121
    -55
      include/utl/meta/invoke.h

+ 121
- 55
include/utl/meta/invoke.h View File

@@ -66,14 +66,13 @@ namespace meta{
template <typename _Tp>
struct identity {
#if defined (UTL_WORKAROUND_CWG_1558)
// decltype via use_() using Ts... to set the apply type
// redirect unused Ts... via void_t
template <typename... Ts>
using _dummy = void_t<Ts...>;
using apply = _Tp; //!< identity is invokable, must also have apply
using apply = first_of<_Tp, void_t<Ts...>>; //!< identity is invokable, must also have apply
#else
template <typename...>
using apply = _Tp; //!< identity is invokable, must also have apply
#endif
#endif
using type = _Tp; //!< identity
};
@@ -82,40 +81,68 @@ namespace meta{
using identity_t = type_<identity<_Tp>>;
//! @}
//! Is evaluable trait
//! Is applicable trait
//! @{
namespace detail {
// we check for template \p F to be a metafunction with parameters \p T
template<template<typename...> class F, typename... T>
struct is_evaluable_ {
struct is_applicable_ {
template<template<typename...> class G, typename = G<T...>>
static true_ check (int);
static true_ check (int); //< T.. can be passed to G
template<template<typename...> class>
static false_ check (...);
static false_ check (...); //< all other combinations
using type = decltype(check<F>(0));
};
// we check for template \p F with integral constant parameters \p Is of type \p T
// template<typename T, template <T...> class F, T... Is>
// struct is_evaluable_i_ {
// template<typename TT, template <TT...> class G, class = G<Is...>>
// static true_ check (int);
// template<typename, template<typename...> class>
// static false_ check (...);
//
// using type = decltype(check<T, F>(0));
// };
template <typename Fn, typename... Args>
using use_ = typename Fn::template apply<Args...>;
template<typename F, typename... T>
struct is_applicable_q_ {
template<typename G, typename Ret= type_<use_<G, T...>>>
static Ret check (int); //< T.. can be passed to G
template<typename...>
static nil_ check (...); //< all other combinations
using type = decltype(check<F>(0));
};
template<typename T, template <T...> class F, T... Is>
struct is_applicable_i_ {
template<typename TT, template<TT...> class G, typename =G<Is...>>
static true_ check (int); //< Is... can be passed to G
template<typename TT, template<TT...> class G>
static false_ check (...); //< all other combinations
using type = decltype(check<T, F>(0));
};
}
//! check if we can instantiate \p F with parameters \p T
template<template<typename...> class F, typename... T>
using is_evaluable = type_<
detail::is_evaluable_<F, T...>
using is_applicable_t = type_<
detail::is_applicable_<F, T...>
>;
//! check if we can instantiate \p Q with parameters \p T and the instant
//! is different from \c nil_
template<typename Q, typename... T>
using is_applicable_qt = type_ <
// Extra check for quoted metafunctions to check return type
if_ <
not_same_<
type_ <detail::is_applicable_q_ <Q, T...>>,
nil_
>,
true_,
false_
>
>;
//! check if we can instantiate \p F with parameters \p Is of type \p T
template <typename T, template<T...> class F, T... Is>
using is_applicable_it = type_<
detail::is_applicable_i_<T, F, Is...>
>;
// template <typename T, template<T...> class F, T... Is>
// using is_evaluable_i = type_<detail::is_evaluable_i_<T, F<Is...>>>;
//! @}
@@ -128,11 +155,12 @@ namespace meta{
using type = F<Ts...>;
};
// template<typename T, template<T...> class F, T... Is>
// struct defer_i_ {
// using type = F<Is...>;
// };
//!
template<typename T, template<T...> class F, T... Is>
struct defer_i_ {
using type = F<Is...>;
};
//! \note
//! We use struct instead of:
//! template<template<typename...> class F, typename... Ts>
//! using defer_ = F<Ts...>;
@@ -150,18 +178,18 @@ namespace meta{
//! defer alias template for F<Ts...>
template<template<class...> class F, class... Ts>
using defer = if_<
is_evaluable<F, Ts...>,
detail::is_applicable_<F, Ts...>,
detail::defer_<F, Ts...>,
nil_
nil_ //!< This should be identity<nil_> if nil_ was empty
>;
//! defer_i alias template for F<T, Is...>
// template <typename T, template<T...> class F, T... Is>
// using defer_i = if_ <
// is_evaluable_i<T, F<Is...>>,
// detail::defer_i_<F, Is...>,
// nil_
// >;
template <typename T, template<T...> class F, T... Is>
using defer_i = if_ <
detail::is_applicable_i_<T, F, Is...>,
detail::defer_i_<T, F, Is...>,
nil_ //!< This should be identity<nil_> if nil_ was empty
>;
//! @}
/*!
@@ -171,27 +199,35 @@ namespace meta{
template <template <typename...> class F>
struct quote {
template <typename... Args>
using apply = type_<defer<F, Args...>>; //!< defer here to avoid DR1430
using apply = type_<
defer<F, Args...> //!< defer here to avoid DR1430
>;
};
//! Wrap a template \p F taking literals of type \p T into an Invokable
// template <typename T, template <T...> class F>
// struct quote_i {
// // requires meta::Integral
// template <typename... Is>
// using apply = type_<
// defer_i<T, F, Is...> //!< defer here to avoid DR1430
// >;
// };
template <typename T, template <T...> class F>
struct quote_i {
// requires meta::Integral
template <typename... Ts>
using apply = type_<
defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
>;
};
/*!
* Invoke the nested apply metafunction from \c Fn
* with the arguments \c Args.
* requires Invocable(Fn)
*/
template <typename Fn, typename... Args>
using invoke = typename Fn::template apply<Args...>;
/*!
* Invoke the nested apply metafunction from \c Fn
* with the arguments \c Args.
*/
template <typename Fn, typename... Args>
using invoke_t = type_<invoke <Fn, Args...>>;
//! compose
//! @{
namespace detail {
@@ -214,34 +250,64 @@ namespace meta{
using apply = invoke<Fn0, Args...>;
};
}
/*!
* Create an invokable from other invokables by composition
* ex:
* compose<Fns...> will result to something like F0<F1<F2<F3<...>>>>
* Create an invokable from other invocables by composition.
* \note
* This implies from N invocables in \p Fns the first N-1 has to be unary.
* That because of the "return" type of metafunction. They can only return one
* type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
* \example
* \code
* static_assert(std::is_same<
* invoke<compose<F1, F2, F3>, int>,
* F1 <F2 <F3 <int>>>
* >, "" );
* \endcode
*/
template <typename... Fns>
using compose = detail::compose_<Fns...>;
//! @}
//! Applies the Invocable \p Fn by binding the arguments \p Ts
//! to the \e front of \p Fn.
/*!
* Applies the Invocable \p Fn by binding the arguments \p Ts
* to the front of \p Fn.
*/
template<typename Fn, typename... Ts>
struct bind_front {
template<typename... Us>
using apply = invoke<Fn, Ts..., Us...>;
};
//! Applies the Invocable \p Fn by binding the arguments \p Ts
//! to the \e back of \p Fn.
/*!
* Applies the Invocable \p Fn by binding the arguments \p Ts
* to the back of \p Fn.
*/
template<typename Fn, typename... Ts>
struct bind_back {
template<typename... Us>
using apply = invoke<Fn, Us..., Ts...>;
};
/*
* ========== predicates ============
*/
template <typename T1>
struct same_as {
template < typename T2>
struct apply : same_<T1, T2> { };
};
template <typename T1>
struct not_same_as {
template < typename T2>
struct apply : not_same_<T1, T2> { };
};
//! @}
}}
//! @}
#endif /* __utl_meta_utility_h__ */
#endif /* __utl_meta_invoke_h__ */

Loading…
Cancel
Save