/*!
* \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
#include
/*!
* \ingroup meta
* \defgroup invoke
*
*/
//! @{
namespace utl {
namespace meta{
/*!
* \name meta:: invoke
*
* A meta-programming invoke() analogous. A meta:: `invocable` shall contain a nested
* template type named `apply` which is bind to actual invocable meta-function.
*/
//! @{
/*!
* *invocable* 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>;
//! @}
//! 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
using use_ = typename Fn::template apply;
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 = decltype(check(0));
};
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 instantiate \p Q with parameters \p T and the instant
//! is different from \c nil_
template
using is_applicable_qt = eval <
// Extra check for quoted metafunctions to check return type
if_ <
not_same_<
eval >,
nil_
>,
true_,
false_
>
>;
//! 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 [1] and is used
//! as suggested by Roy Crihfield in [2].
//! In short, this is due to language's inability to expand Ts... into
//! a fixed parameter list of an alias template.
//!
//! [1]: https://wg21.link/cwg1430
//! [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_ //!< This should be identity if nil_ was empty
>;
//! defer_i alias template for F
template class F, T... Is>
using defer_i = if_ <
detail::is_applicable_i_,
detail::defer_i_,
nil_ //!< This should be identity if nil_ was empty
>;
//! @}
/*!
* quote is a higher-order primitive that wraps an n-ary Metafunction
* to create a corresponding Metafunction Class (Invocable).
*/
template class F>
struct quote {
template
using apply = eval<
defer //!< defer here to avoid DR1430
>;
};
//! Wrap a template \p F taking literals 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
>;
};
/*!
* Invoke the nested apply meta-function from \c Fn
* with the arguments \c Args.
* \note
* This is like 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 >;
//! compose
//! @{
namespace detail {
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 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, int>,
* F1 >>
* >, "" );
* \endcode
*/
template
using compose = detail::compose_;
//! @}
/*!
* 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 < typename T2>
struct apply : same_ { };
};
template
struct not_same_as {
template < typename T2>
struct apply : not_same_ { };
};
}}
//! @}
//! @}
#endif /* __utl_meta_invoke_h__ */