/*!
* \file invoke.h
* \brief Template meta-programming utilities for callables
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more detail.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef __utl_meta_invoke_h__
#define __utl_meta_invoke_h__
#include
#include
#include
#include
/*!
* \ingroup meta
* \defgroup invoke
*
*/
//! @{
namespace utl {
namespace meta{
/*!
* \name meta::invoke
*
* A meta-programming invoke() analogous. A \c meta::invocable shall contain a nested
* template type named \b apply which is bind to actual invocable meta-function.
*
* - We can use \c wrap<> or even better \c quote<> in order to wrap a metafunction to a type (metafunction class)
* - We can pass these wrapped types to other metafunctions
* - We can \c invoke<> the inner \c apply from a wrapped metafunction class.
*/
//! @{
/*!
* identity, identity_t.
*/
//! @{
template
struct identity {
#if defined (UTL_WORKAROUND_CWG_1558)
// redirect unused Ts... via void_t
template
using apply = first_of<_Tp, void_t>; //!< identity is invokable, must also have apply
#else
template
using apply = _Tp; //!< identity is invokable, must also have apply
#endif
using type = _Tp; //!< identity
};
//! identity type alias
template
using identity_t = eval>;
//! @}
/*!
* invoke, invoke_t
*/
//! @{
/*!
* Invoke the nested apply meta-function from \c Fn with the arguments \c Args.
* \note
* This is an analogous to the std::invoke()
*/
template
using invoke = typename Fn::template apply;
/*!
* Evaluate the invocation of the nested apply metafunction from \p Fn
* with the arguments \p Args.
*/
template
using invoke_t = eval< invoke >;
//! @}
//! wrap
//! @{
/*!
* wrap is a higher-order primitive that wraps an n-ary Metafunction
* to create a corresponding Metafunction Class (Invocable). This way
* we can pass Metafunctions as types to other metafunctions and let
* them \c invoke the inner templated apply
*/
template class F>
struct wrap {
template
using apply = F;
};
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
template class F>
struct wrap_i {
// requires meta::Integral
template
using apply = F;
};
//! @}
//! Is applicable trait
//! @{
namespace detail {
template class F, typename... T>
struct is_applicable_ {
template class G, typename = G>
static true_ check (int); //< T.. can be passed to G
template class>
static false_ check (...); //< all other combinations
using type = decltype(check(0));
};
template
struct is_applicable_q_ {
template>
static Ret check (int); //< T.. can be passed to G
template
static nil_ check (...); //< all other combinations
using type = if_ <
not_same_<
nil_,
decltype(check(0))
>, true_, false_
>;
//!\note
//! check doesn't return \c true_ or \c false_. The reason is that the \p F is
//! probably quoted/deferred. This implies an embedded is_applicable<> check
//! inside defer<> and so its guaranteed to be well formed.
//! Thus we return the actual evaluated type and make the check for nil_
};
template class F, T... Is>
struct is_applicable_i_ {
template class G, typename = G>
static true_ check (int); //< Is... can be passed to G
template class G>
static false_ check (...); //< all other combinations
using type = decltype(check(0));
};
}
//! check if we can instantiate \p F with parameters \p T
template class F, typename... T>
using is_applicable_t = eval<
detail::is_applicable_
>;
//! check if we can invoke \p Q with parameters \p T
template
using is_applicable_qt = eval <
detail::is_applicable_q_
>;
//! check if we can instantiate \p F with parameters \p Is of type \p T
template class F, T... Is>
using is_applicable_it = eval<
detail::is_applicable_i_
>;
//! @}
//! defer
//! @{
namespace detail {
//! @{
template class F, typename... Ts>
struct defer_ {
using type = F;
};
template class F, T... Is>
struct defer_i_ {
using type = F;
};
//! \note
//! We use struct instead of:
//! template class F, typename... Ts>
//! using defer_ = F;
//!
//! The use of struct here is due to Core issue 1430 [\ref link1 1] and is used
//! as suggested by Roy Crihfield in [\ref link2 2].
//! In short, this is due to language's inability to expand Ts... into
//! a fixed parameter list of an alias template.
//!
//! \anchor link1 [1]: https://wg21.link/cwg1430
//! \anchor link2 [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
//! @}
}
//! defer alias template for F
template class F, class... Ts>
using defer = if_<
detail::is_applicable_,
detail::defer_,
nil_ //!< Safe, nil_ is dereferencable
>;
//! defer_i alias template for F
template class F, T... Is>
using defer_i = if_ <
detail::is_applicable_i_,
detail::defer_i_,
nil_ //!< Safe, nil_ is dereferencable
>;
//! @}
//! quote
//! @{
/*!
* quote deferred is a higher-order primitive that wraps an n-ary Metafunction
* to create a corresponding Metafunction Class (Invocable) using defer<> to
* postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.
* Again this way we can pass Metafunctions as types to other metafunctions and let
* them \c invoke the inner templated apply
*/
template class F>
struct quote {
template
using apply = eval<
defer //!< defer here to avoid DR1430
>;
};
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
template class F>
struct quote_i {
// requires meta::Integral
template
using apply = eval<
defer_i //!< defer here to avoid DR1430
>;
};
//! @}
//! compose
//! @{
namespace detail {
template class... Fns> struct compose_f_ {};
// recursive call to all invokes
template class Fn0,
template class... Fns>
struct compose_f_ {
template
using apply = invoke<
quote,
invoke, Args...>
>;
};
// Termination specialization, finally pass the arguments
template class Fn0>
struct compose_f_ {
template
using apply = invoke, Args...>;
};
template struct compose_ {};
// recursive call to all invokes
template
struct compose_ {
template
using apply = invoke<
Fn0,
invoke, Args...>
>;
};
// Termination specialization, finally pass the arguments
template
struct compose_ {
template
using apply = invoke;
};
}
/*!
* Create an invocable from other invocables(quoted metafunctions) by composition.
* \note
* This implies from N invocables in \p 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.
* \example
* \code
* static_assert( std::is_same<
* invoke, quote, quote>, int>, F1>>
* >, "");
* \endcode
*/
template
using compose = detail::compose_;
/*!
* Create an invocable from other metafunctions by composition.
* \note
* This implies from N invocables in \p 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.
* \example
* \code
* static_assert( std::is_same<
* invoke, int>, F1 >>
* >, "");
* \endcode
*/
template class... Fns>
using compose_f = detail::compose_f_;
//! @}
/*!
* Applies the invocable \p Fn by binding the arguments \p Ts
* to the front of \p Fn.
*/
template
struct bind_front {
template
using apply = invoke;
};
/*!
* Applies the Invocable \p Fn by binding the arguments \p Ts
* to the back of \p Fn.
*/
template
struct bind_back {
template
using apply = invoke;
};
/*
* ========== meta:: predicates ============
*/
template
struct same_as {
template
struct apply : same_ { };
};
template
struct not_same_as {
template
struct apply : not_same_ { };
};
}}
//! @}
//! @}
#endif /* __utl_meta_invoke_h__ */