W:/Work/Software/Libraries/utl/include/utl/meta/invoke.h

Create an invocable from other invocables(quoted metafunctions) by composition.

Note
  This implies from N invocables in `Fns` the first N-1 has to be unary. Thats 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.

static_assert( std::is_same<
invoke<compose<quote<F1>, quote<F2>, quote<F3>>, int>, F1<F2<F3<int>>>
>, "");
#ifndef __utl_meta_invoke_h__
#define __utl_meta_invoke_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/detection.h>
#include <utl/meta/operations.h>
namespace utl {
namespace meta{
template <typename _Tp>
struct identity {
#if defined (UTL_WORKAROUND_CWG_1558)
// redirect unused Ts... via void_t
template <typename... Ts>
using apply = first_of<_Tp, void_t<Ts...>>;
#else
template <typename...>
using apply = _Tp;
#endif
using type = _Tp;
};
template <typename _Tp>
using identity_t = eval<identity<_Tp>>;
template <typename Fn, typename... Args>
using invoke = typename Fn::template apply<Args...>;
template <typename Fn, typename... Args>
using invoke_t = eval< invoke <Fn, Args...>>;
template <template <typename...> class F>
struct wrap {
template <typename... Args>
using apply = F<Args...>;
};
template <typename T, template <T...> class F>
struct wrap_i {
// requires meta::Integral
template <typename... Ts>
using apply = F<Ts::type::value...>;
};
namespace detail {
template<template<typename...> class F, typename... T>
struct is_applicable_ {
template<template<typename...> class G, typename = G<T...>>
static true_ check (int); //< T.. can be passed to G
template<template<typename...> class>
static false_ check (...); //< all other combinations
using type = decltype(check<F>(0));
};
template<typename F, typename... T>
struct is_applicable_q_ {
template<typename G, typename Ret = invoke_t<G, T...>>
static Ret check (int); //< T.. can be passed to G
template<typename...>
static nil_ check (...); //< all other combinations
using type = if_ <
not_same_<
nil_,
decltype(check<F>(0))
>, true_, false_
>;
};
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));
};
}
template<template<typename...> class F, typename... T>
using is_applicable_t = eval<
detail::is_applicable_<F, T...>
>;
template<typename Q, typename... T>
using is_applicable_qt = eval <
detail::is_applicable_q_ <Q, T...>
>;
template <typename T, template<T...> class F, T... Is>
using is_applicable_it = eval<
detail::is_applicable_i_<T, F, Is...>
>;
namespace detail {
template<template<typename...> class F, typename... Ts>
struct defer_ {
using type = F<Ts...>;
};
template<typename T, template<T...> class F, T... Is>
struct defer_i_ {
using type = F<Is...>;
};
}
template<template<class...> class F, class... Ts>
using defer = if_<
detail::is_applicable_<F, Ts...>,
detail::defer_<F, Ts...>,
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_
>;
template <template <typename...> class F>
struct quote {
template <typename... Args>
using apply = eval<
defer<F, Args...>
>;
};
template <typename T, template <T...> class F>
struct quote_i {
// requires meta::Integral
template <typename... Ts>
using apply = eval<
defer_i<T, F, Ts::type::value...>
>;
};
namespace detail {
template <template <typename...> class... Fns> struct compose_f_ {};
// recursive call to all invokes
template <template <typename...> class Fn0,
template <typename...> class... Fns>
struct compose_f_<Fn0, Fns...> {
template <typename... Args>
using apply = invoke<
quote<Fn0>,
invoke<compose_f_<Fns...>, Args...>
>;
};
// Termination specialization, finally pass the arguments
template <template <typename...> class Fn0>
struct compose_f_<Fn0> {
template <typename ...Args>
using apply = invoke<quote<Fn0>, Args...>;
};
template<typename ...Fns> struct compose_ {};
// recursive call to all invokes
template<typename Fn0, typename ...Fns>
struct compose_<Fn0, Fns...> {
template <typename ...Args>
using apply = invoke<
Fn0,
invoke<compose_<Fns...>, Args...>
>;
};
// Termination specialization, finally pass the arguments
template<typename Fn0>
struct compose_<Fn0> {
template <typename... Args>
using apply = invoke<Fn0, Args...>;
};
}
template <typename... Fns>
using compose = detail::compose_<Fns...>;
template <template <typename...> class... Fns>
using compose_f = detail::compose_f_<Fns...>;
template<typename Fn, typename... Ts>
struct bind_front {
template<typename... Us>
using apply = invoke<Fn, Ts..., Us...>;
};
template<typename Fn, typename... Ts>
struct bind_back {
template<typename... Us>
using apply = invoke<Fn, Us..., Ts...>;
};
/*
* ========== meta:: 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_invoke_h__ */