DEV: meta reshape

This commit is contained in:
Christos Houtouridis
2019-10-22 20:06:10 +03:00
parent 5f6eef3478
commit 984a073f29
21 changed files with 1055 additions and 708 deletions
+12 -11
View File
@@ -689,17 +689,18 @@ namespace _1wire_i_det {
meta::void_t <
// typename _Tp::Speed,
// typename _Tp::Command,
meta::use_if_same_t <try_reset_t <_Tp>, bool>,
meta::use_if_same_t <try_rx1_t <_Tp>, byte_t>,
//meta::use_if_same_t <try_rx2_t <_Tp>, size_t>,
meta::use_if_same_t <try_tx1_t <_Tp>, byte_t>,
//meta::use_if_same_t <try_tx2_t <_Tp>, size_t>,
meta::use_if_same_t <try_match_t<_Tp>, void>,
meta::use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
meta::use_if_same_t <try_skip_t<_Tp>, void>,
meta::use_if_same_t <try_skip_n_ovdr_t<_Tp>, void>,
meta::use_if_same_t <try_first_t <_Tp>, _1wire_id_t>,
meta::use_if_same_t <try_next_t <_Tp>, _1wire_id_t>
// meta::use_if_same_t <try_reset_t <_Tp>, bool>,
// meta::use_if_same_t <try_rx1_t <_Tp>, byte_t>,
// //meta::use_if_same_t <try_rx2_t <_Tp>, size_t>,
// meta::use_if_same_t <try_tx1_t <_Tp>, byte_t>,
// //meta::use_if_same_t <try_tx2_t <_Tp>, size_t>,
// meta::use_if_same_t <try_match_t<_Tp>, void>,
// meta::use_if_same_t <try_match_n_ovdr_t<_Tp>, void>,
// meta::use_if_same_t <try_skip_t<_Tp>, void>,
// meta::use_if_same_t <try_skip_n_ovdr_t<_Tp>, void>,
// meta::use_if_same_t <try_first_t <_Tp>, _1wire_id_t>,
// meta::use_if_same_t <try_next_t <_Tp>, _1wire_id_t>
void
> //!^ SFINAE may apply
> : meta::true_ {};
} // namespace _1wire_i_det
+7 -6
View File
@@ -261,12 +261,13 @@ namespace utl {
struct is_i2c_ <_Tp,
meta::void_t <
typename _Tp::Sequence,
meta::use_if_same_t <uint32_t,try_cclk_t <_Tp>>,
meta::use_if_same_t <void, try_clk_t <_Tp>>,
meta::use_if_same_t <void, try_start_t <_Tp>>,
meta::use_if_same_t <void, try_stop_t <_Tp>>,
meta::use_if_same_t <byte_t, try_rx_data_t <_Tp>>,
meta::use_if_same_t <bool, try_tx_data_t <_Tp>>
// meta::use_if_same_t <uint32_t,try_cclk_t <_Tp>>,
// meta::use_if_same_t <void, try_clk_t <_Tp>>,
// meta::use_if_same_t <void, try_start_t <_Tp>>,
// meta::use_if_same_t <void, try_stop_t <_Tp>>,
// meta::use_if_same_t <byte_t, try_rx_data_t <_Tp>>,
// meta::use_if_same_t <bool, try_tx_data_t <_Tp>>
void
>
> : meta::true_ { };
}
+12 -12
View File
@@ -75,9 +75,9 @@ namespace utl {
//! \name SPI implementation specific functions
//!@{
template <spi::bitOrder B =BitOrder> constexpr
meta::use_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
meta::enable_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
template <spi::bitOrder B =BitOrder> constexpr
meta::use_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
meta::enable_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
template <spi::cpol C =CPOL> static constexpr bool clkHigh () {
return !static_cast<bool>(C);
}
@@ -113,9 +113,9 @@ namespace utl {
byte_t _tx_data (byte_t out) { return _tx_data_impl (out); }
template <spi::cpha C =CPHA>
meta::use_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
meta::enable_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
template <spi::cpha C =CPHA>
meta::use_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
//!@}
//! Data members
@@ -134,7 +134,7 @@ namespace utl {
*/
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
template <spi::cpha C>
meta::use_if_t <(C == spi::cpha::LOW), byte_t>
meta::enable_if_t <(C == spi::cpha::LOW), byte_t>
spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
byte_t in {};
SCLK (clkL_);
@@ -158,7 +158,7 @@ namespace utl {
*/
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
template <spi::cpha C>
meta::use_if_t <(C == spi::cpha::HIGH), byte_t>
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t>
spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
byte_t in {};
SCLK (clkL_);
@@ -207,9 +207,9 @@ namespace utl {
//! \name SPI implementation specific functions
//!@{
template <spi::bitOrder B =BitOrder> constexpr
meta::use_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
meta::enable_if_t <(B == spi::bitOrder::LSB_First), void> shift (byte_t& b) { b <<=1; }
template <spi::bitOrder B =BitOrder> constexpr
meta::use_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
meta::enable_if_t <(B == spi::bitOrder::MSB_First), void> shift (byte_t& b) { b >>=1; }
template <spi::cpol C =CPOL> static constexpr bool clkHigh () {
return !static_cast<bool>(C);
}
@@ -241,9 +241,9 @@ namespace utl {
byte_t _tx_data (byte_t out) final { return _tx_data_impl (out); }
template <spi::cpha C =CPHA>
meta::use_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
meta::enable_if_t <(C == spi::cpha::LOW), byte_t> _tx_data_impl (byte_t out);
template <spi::cpha C =CPHA>
meta::use_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t> _tx_data_impl (byte_t out);
//!@}
//! Data members
@@ -262,7 +262,7 @@ namespace utl {
*/
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
template <spi::cpha C>
meta::use_if_t <(C == spi::cpha::LOW), byte_t>
meta::enable_if_t <(C == spi::cpha::LOW), byte_t>
spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
byte_t in {};
SCLK (clkL_);
@@ -286,7 +286,7 @@ namespace utl {
*/
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder>
template <spi::cpha C>
meta::use_if_t <(C == spi::cpha::HIGH), byte_t>
meta::enable_if_t <(C == spi::cpha::HIGH), byte_t>
spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) {
byte_t in {};
SCLK (clkL_);
+25
View File
@@ -47,6 +47,14 @@ namespace utl {
template <typename T>
using _ref_t = std::add_lvalue_reference_t<T>;
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_same_t = meta::eval<
meta::enable_if<
meta::same_<_T1, _T2>::value, _Ret
>
>;
/*!
* Same
*/
@@ -501,6 +509,23 @@ namespace utl {
};
#else
namespace details {
// template <typename B> using try_op_not_ = decltype(!std::declval<cref_<B>>());
// template <typename B> using try_op_eq_ = decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>());
// template <typename B> using try_op_neq_ = decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>());
// template <typename B> using try_op_and_ = decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>());
// template <typename B> using try_op_or_ = decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>());
//
// template <typename B>
// struct is_boolean__ {
// using type = meta::and_ <
// meta::is_detected<B, try_op_not_>,
// meta::is_detected<B, try_op_eq_>,
// meta::is_detected<B, try_op_neq_>,
// meta::is_detected<B, try_op_and_>,
// meta::is_detected<B, try_op_or_>
// >;
// };
template <typename B, typename = void>
struct is_boolean_ {
using type = meta::false_;
+15 -12
View File
@@ -425,10 +425,11 @@ namespace utl {
typename _Tp::difference_type,
typename _Tp::pointer,
typename _Tp::reference,
meta::use_if_same_t <
typename _Tp::iterator_category,
std::output_iterator_tag
>
// meta::use_if_same_t <
// typename _Tp::iterator_category,
// std::output_iterator_tag
// >
void
>
> : meta::true_ {};
}
@@ -702,10 +703,11 @@ namespace utl {
typename _Tp::difference_type,
typename _Tp::pointer,
typename _Tp::reference,
meta::use_if_same_t <
typename _Tp::iterator_category,
std::input_iterator_tag
>
// meta::use_if_same_t <
// typename _Tp::iterator_category,
// std::input_iterator_tag
// >
void
>
> : meta::true_ {};
}
@@ -986,10 +988,11 @@ namespace utl {
typename _Tp::difference_type,
typename _Tp::pointer,
typename _Tp::reference,
meta::use_if_same_t <
typename _Tp::iterator_category,
std::input_iterator_tag
>
// meta::use_if_same_t <
// typename _Tp::iterator_category,
// std::input_iterator_tag
// >
void
>
> : meta::true_ {};
}
+92 -19
View File
@@ -1,8 +1,8 @@
/*!
* \file detection.h
* \brief Detection idiom based on WG21's N4502[1] from Walter E. Brown
* \brief Detection idiom based on WG21's N4502 [\ref n4502 1] from Walter E. Brown
*
* [1]: www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
* \anchor n4502 [1]: www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
*
* Copyright (C) 2018-2019 Christos Choutouridis
*
@@ -23,7 +23,7 @@
#define __utl_meta_detection_h__
#include <utl/core/impl.h>
#include <utl/meta/logical.h>
#include <utl/meta/operations.h>
#include <type_traits>
/*!
@@ -57,7 +57,8 @@ namespace meta {
//! @}
/*!
* Not a type to use in detected idiom
* Not a type to use in detected idiom. This type can
* not be constructed, destructed or copied
*/
struct nat_ {
nat_() = delete;
@@ -108,11 +109,9 @@ namespace meta {
* \example
* \code
* // archetypal alias for a copy assignment operation
* template< class T >
* using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
* template< class T > using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
*
* template< class T >
* using is_copy_assignable = is_detected< T, copy_assign_t >;
* template< class T > using is_copy_assignable = is_detected< copy_assign_t, T >;
* \endcode
*/
template <template<typename...> class Op, typename... Args>
@@ -121,41 +120,115 @@ namespace meta {
//! Detection predicate
template< template<typename...> class Op, typename... Args>
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
//! @}
/*!
* Detection idiom toolkit
* Detection tool that evaluates to Op<Args...> if it's valid and to nat_ if not
*
* \param Op metafunction detector
* \param Args... The arguments to pass to \p Op and check if is well formed
* \return The result type
* \arg Op<Args...> if is well formed
* \arg nat_ if Op<Args...> is ill formed
* \example
* \code
* template <typename T> using try_type = typename T::type; // detector
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
* static_assert( std::is_same<nat_, detected_t<try_type, A<int>> >(), ""); // detection failed
* static_assert( std::is_same<A<int>&, detected_t<try_ppT, A<int>> >(), ""); // detection succeed
*
* // if mFun<int, int> is well formed
* static_assert(std::is_same< mFun<int, int>, detected_t<mFun, int, int> >(), "");
* \endcode
*/
//! @{
//! evaluates to evaluation of Op<Args...> if it's valid and to nat_ if not
template <template<typename...> class Op, typename... Args>
using detected_t = eval <
detail::detector<nat_, void, Op, Args...>
>;
//! evaluates to evaluation of Op<Args...> if it's valid and to \p Default if not
/*!
* Detection tool that evaluates to Op<Args...> if it's valid and to \p Default if not
*
* \param Default The resulting type if detection fail
* \param Op metafunction detector
* \param Args... The arguments to pass to \p Op and check if is well formed
* \return The result type
* \arg Op<Args...> if is well formed
* \arg Default if Op<Args...> is ill formed
* \example
* \code
* template <typename T> using try_type = typename T::type; // detector
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
* static_assert( std::is_same<Foo, detected_or_t<Foo, try_type, A<int>> >(), ""); // detection failed
* static_assert( std::is_same<A<int>&, detected_or_t<Foo, try_ppT, A<int>> >(), ""); // detection succeed
*
* // if mFun<int, int> is well formed
* static_assert(std::is_same< mFun<int, int>, detected_or_t<void, mFun, int, int> >(), "");
* \endcode
*/
template <typename Default,
template<typename...> class Op, typename... Args>
using detected_or_t = eval <
detail::detected_or<Default, Op, Args...>
>;
//! evaluates to true_ if evaluation of Op<Args...> is \p Expected and to false_ if not
/*!
* Detection tool that evaluates to true_ if evaluation of Op<Args...>
* is \p Expected and to false_ if not
*
* \param Expected The expected resulting type if detection succeed
* \param Op metafunction detector
* \param Args... The arguments to pass to \p Op and check if is well formed
* \return The result type
* \arg true_ if Op<Args...> is well formed and evaluate to Expected
* \arg false_ Any other case
* \example
* \code
* template <typename T> using try_type = typename T::type; // detector
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
* static_assert( std::is_same<false_, is_detected_exact<int, try_type, A<int>> >(), ""); // detection failed
* static_assert( std::is_same<true_, is_detected_exact<A<int>&, try_ppT, A<int>> >(), ""); // detection succeed
*
* // if mFun<int, int> is well formed
* static_assert(std::is_same< true_, is_detected_exact<mFun<int, int>, mFun, int, int> >(), "");
* \endcode
*/
template <typename Expected,
template<typename...> class Op, typename... Args >
using is_detected_exact = same_<Expected, detected_t<Op, Args...> >;
using is_detected_exact = eval <
same_<Expected, detected_t<Op, Args...>>
>;
//! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
template <typename Expected,
template<typename...> class Op, typename... Args >
constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
//! evaluates to true_ if evaluation of Op<Args...> is convertible to \p To
//! and to false_ if not
/*!
* Detection tool that evaluates to true_ if evaluation of Op<Args...> is convertible
* to \p To and to false_ if not
*
* \param To The to convert to if detection succeed
* \param Op metafunction detector
* \param Args... The arguments to pass to \p Op and check if is well formed
* \return The result type
* \arg true_ if Op<Args...> is well formed and convertible to To
* \arg false_ Any other case
* \example
* \code
* template <typename T> using try_type = typename T::type; // detector
* template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
* static_assert( std::is_same<false_, is_detected_convertible<Foo, try_type, A<int>> >(), ""); // detection failed
* static_assert( std::is_same<true_, is_detected_convertible<A<int>&&, try_ppT, A<int>> >(), "");// detection succeed
*
* // if mFun<int, int> is well formed but not convertible to Foo
* static_assert(std::is_same< false_, is_detected_convertible<Foo, mFun, int, int> >(), "");
* \endcode
*/
template <typename To,
template<typename...> class Op, typename... Args >
using is_detected_convertible = std::is_convertible< detected_t<Op, Args...>, To >;
using is_detected_convertible = eval <
std::is_convertible< detected_t<Op, Args...>, To >
>;
//! evaluates to true if evaluation of Op<Args...> is convertible to \p To
//! and to false if not
-113
View File
@@ -1,113 +0,0 @@
/*!
* \file pack.h
* \brief Template meta-programming parameter pack container
*
* Copyright (C) 2018-2019 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 details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_idx_sequence_h__
#define __utl_meta_idx_sequence_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
/*!
* \ingroup meta
* \defgroup index_sequence
*/
//! @{
namespace utl {
namespace meta {
/*!
* Class template integer_sequence
*/
template<typename _Tp, _Tp... _Idx>
struct integer_sequence {
using value_type = _Tp;
static constexpr size_t size() noexcept {
return sizeof...(_Idx);
}
};
//! Alias template index_sequence
template<index_t... _Idx>
using index_sequence = integer_sequence<index_t, _Idx...>;
//! make_integer_sequence
//! @{
namespace detail {
// Stores a tuple of indices
template<size_t... Idxs> struct index_tuple { };
// Concatenates two index_tuples.
template<typename It1, typename It2> struct it_cat_;
template<size_t... It1, size_t... It2>
struct it_cat_ <index_tuple<It1...>, index_tuple<It2...>> {
using type = index_tuple<It1..., (It2 + sizeof...(It1))...>;
};
// Builds an index_tuple<0, 1, 2, ..., _Num-1>.
template<size_t _Num>
struct make_index_tuple_
: it_cat_<eval<make_index_tuple_<_Num / 2>>,
eval<make_index_tuple_<_Num - _Num / 2>>>
{ };
// termination specialization for 1
template<>
struct make_index_tuple_<1> {
using type = index_tuple<0>;
};
// termination specialization for 0
template<>
struct make_index_tuple_<0> {
using type = index_tuple<>;
};
// factory type
template<typename _Tp, _Tp _Num,
typename _ISeq = eval<make_index_tuple_<_Num>>>
struct make_integer_sequence_;
template<typename _Tp, _Tp _Num, size_t... _Idx>
struct make_integer_sequence_<_Tp, _Num, index_tuple<_Idx...>> {
static_assert( _Num >= 0,
"Cannot make integer sequence of negative length" );
using type = integer_sequence<_Tp, static_cast<_Tp>(_Idx)...>;
};
}
//! Alias template make_integer_sequence
//! Complexity \f$ O(log N) \f$
template<typename _Tp, _Tp N>
using make_integer_sequence = eval<detail::make_integer_sequence_<_Tp, N>>;
//! Alias template make_index_sequence
//! Complexity \f$ O(log N) \f$
template<index_t N>
using make_index_sequence = make_integer_sequence<index_t, N>;
//! Alias template index_sequence_for
//! Complexity \f$ O(log N) \f$
//! where N is sizeof...(_Ts)
template<typename... _Ts>
using index_sequence_for = make_index_sequence<sizeof...(_Ts)>;
//! @}
}}
//! @}
#endif /* __utl_meta_idx_sequence_h__ */
+59 -50
View File
@@ -21,7 +21,8 @@
#define __utl_meta_integralconstant_h__
#include <utl/core/impl.h>
#include <type_traits>
#include <utility>
/*!
* \ingroup meta
@@ -43,9 +44,9 @@ namespace meta {
using type = nil_;
};
//! Type alias for \p _Tp::type. Used to evaluate/extract return type of metafunctions
template <typename _Tp>
using eval = typename _Tp::type;
//! Type alias for \p Tp::type. Used to evaluate/extract return type of metafunctions
template <typename Tp>
using eval = typename Tp::type;
//! integral_
//! Integral Constant is a holder class for a compile-time value of an integral type.
@@ -53,90 +54,98 @@ namespace meta {
//! An integral constant object is implicitly convertible to the corresponding
//! run-time value of the wrapped integral type
//! @{
template <typename _Tp, _Tp _v>
struct integral_ {
using value_type = _Tp;
using type = integral_<_Tp, _v>;
constexpr operator value_type() const noexcept {
return value;
}
constexpr value_type operator()() const noexcept {
return value;
}
static constexpr _Tp value = _v;
};
template<typename _Tp, _Tp _v>
constexpr _Tp integral_<_Tp, _v>::value;
template <typename Tp, Tp v>
using integral_ = std::integral_constant<Tp, v>;
//! @}
//! Wrappers for basic types
//! @{
//! bool_ type: integral constant wrapper for bool
template<bool _v>
using bool_ = integral_<bool, _v>;
template<bool v>
using bool_ = integral_<bool, v>;
using true_ = bool_<true>; //!< The type used as a compile-time boolean with true value.
using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value.
//! int8_ type: integral constant wrapper for \c int8_t
template<int8_t _v>
using int8_ = integral_<int8_t, _v>;
template<int8_t v>
using int8_ = integral_<int8_t, v>;
//! uint8_ type: integral constant wrapper for \c uint8_t
template<uint8_t _v>
using uint8_ = integral_<uint8_t, _v>;
template<uint8_t v>
using uint8_ = integral_<uint8_t, v>;
//! int16_ type: integral constant wrapper for \c int16_t
template<int16_t _v>
using int16_ = integral_<int16_t, _v>;
template<int16_t v>
using int16_ = integral_<int16_t, v>;
//! uint16_ type: integral constant wrapper for \c uint16_t
template<uint16_t _v>
using uint16_ = integral_<uint16_t, _v>;
template<uint16_t v>
using uint16_ = integral_<uint16_t, v>;
//! int32_ type: integral constant wrapper for \c int32_t
template<int32_t _v>
using int32_ = integral_<int32_t, _v>;
template<int32_t v>
using int32_ = integral_<int32_t, v>;
//! uint32_ type: integral constant wrapper for \c uint32_t
template<uint32_t _v>
using uint32_ = integral_<uint32_t, _v>;
template<uint32_t v>
using uint32_ = integral_<uint32_t, v>;
//! char_ type: integral constant wrapper for \c char
template<char _v>
using char_ = integral_<char, _v>;
template<char v>
using char_ = integral_<char, v>;
//! int_ type: integral constant wrapper for \c int
template<int _v>
using int_ = integral_<int, _v>;
template<int v>
using int_ = integral_<int, v>;
//! long_ type: integral constant wrapper for \c long
template<long _v>
using long_ = integral_<long, _v>;
template<long v>
using long_ = integral_<long, v>;
//! index_ type: integral constant wrapper for \c index_t a.k.a std::size_t
template<index_t _v>
using index_ = integral_<index_t, _v>;
template<index_t v>
using index_ = integral_<index_t, v>;
//! size_ type: integral constant wrapper for \c size_t a.k.a std::size_t
template<size_t _v>
using size_ = integral_<size_t, _v>;
template<size_t v>
using size_ = integral_<size_t, v>;
//! Computes the size of the type \p _Tp.
//! Computes the size of the type \p Tp.
//! Complexity \f$ O(1) \f$.
template <typename _Tp>
using sizeof_ = size_<sizeof(_Tp)>;
template <typename Tp>
using sizeof_ = size_<sizeof(Tp)>;
//! Computes the alignment required for any instance of the type \p _Tp.
//! Computes the alignment required for any instance of the type \p Tp.
//! Complexity \f$ O(1) \f$.
template <typename _Tp>
using alignof_ = size_<alignof(_Tp)>;
template <typename Tp>
using alignof_ = size_<alignof(Tp)>;
//! @}
//! The last position we can express for indexing
using Npos = size_<index_t(-1)>;
//! integer sequence
//! @{
template< class Tp, Tp... Ints >
using integer_sequence = std::integer_sequence<Tp, Ints...>;
template<typename Tp, Tp Num>
using make_integer_sequence = std::make_integer_sequence<Tp, Num>;
//! Alias template index_sequence
template<index_t... Idx>
using index_sequence = integer_sequence<index_t, Idx...>;
//! Alias template make_index_sequence
template<index_t Num>
using make_index_sequence = make_integer_sequence <index_t, Num>;
//! Alias template index_sequence_for
template<typename... Types>
using index_sequence_for = make_index_sequence<sizeof...(Types)>;
//! @}
}}
//!@}
#endif /* __utl_meta_integralconstant_h__ */
+140 -70
View File
@@ -23,8 +23,7 @@
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/detection.h>
#include <utl/meta/selection.h>
#include <utl/meta/logical.h>
#include <utl/meta/operations.h>
/*!
* \ingroup meta
@@ -36,15 +35,19 @@ namespace utl {
namespace meta{
/*!
* \name meta:: invoke
* \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.
* 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.
*/
//! @{
/*!
* *invocable* identity, identity_t.
* identity, identity_t.
*/
//! @{
template <typename _Tp>
@@ -56,7 +59,7 @@ namespace meta{
#else
template <typename...>
using apply = _Tp; //!< identity is invokable, must also have apply
#endif
#endif
using type = _Tp; //!< identity
};
@@ -65,6 +68,49 @@ namespace meta{
using identity_t = eval<identity<_Tp>>;
//! @}
/*!
* 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 <typename Fn, typename... Args>
using invoke = typename Fn::template apply<Args...>;
/*!
* Evaluate the invocation of the nested apply metafunction from \p Fn
* with the arguments \p Args.
*/
template <typename Fn, typename... Args>
using invoke_t = eval< invoke <Fn, Args...>>;
//! @}
//! 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 <template <typename...> class F>
struct wrap {
template <typename... Args>
using apply = F<Args...>;
};
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
template <typename T, template <T...> class F>
struct wrap_i {
// requires meta::Integral
template <typename... Ts>
using apply = F<Ts::type::value...>;
};
//! @}
//! Is applicable trait
//! @{
namespace detail {
@@ -79,22 +125,29 @@ namespace meta{
using type = decltype(check<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= eval<use_<G, T...>>>
static Ret check (int); //< T.. can be passed to G
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
static nil_ check (...); //< all other combinations
using type = decltype(check<F>(0));
using type = if_ <
not_same_<
nil_,
decltype(check<F>(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<typename T, template <T...> class F, T... Is>
struct is_applicable_i_ {
template<typename TT, template<TT...> class G, typename =G<Is...>>
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
@@ -106,26 +159,18 @@ namespace meta{
//! check if we can instantiate \p F with parameters \p T
template<template<typename...> class F, typename... T>
using is_applicable_t = eval<
detail::is_applicable_<F, T...>
detail::is_applicable_<F, T...>
>;
//! check if we can instantiate \p Q with parameters \p T and the instant
//! is different from \c nil_
//! check if we can invoke \p Q with parameters \p T
template<typename Q, typename... T>
using is_applicable_qt = eval <
// Extra check for quoted metafunctions to check return type
if_ <
not_same_<
eval <detail::is_applicable_q_ <Q, T...>>,
nil_
>,
true_,
false_
>
detail::is_applicable_q_ <Q, T...>
>;
//! 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 = eval<
detail::is_applicable_i_<T, F, Is...>
detail::is_applicable_i_<T, F, Is...>
>;
//! @}
@@ -149,75 +194,85 @@ namespace meta{
//! template<template<typename...> class F, typename... Ts>
//! using defer_ = F<Ts...>;
//!
//! The use of struct here is due to Core issue 1430 [1] and is used
//! as suggested by Roy Crihfield in [2].
//! 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.
//!
//! [1]: https://wg21.link/cwg1430
//! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
//! \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<Ts...>
template<template<class...> class F, class... Ts>
using defer = if_<
detail::is_applicable_<F, Ts...>,
detail::defer_<F, Ts...>,
nil_ //!< This should be identity<nil_> if nil_ was empty
detail::is_applicable_<F, Ts...>,
detail::defer_<F, Ts...>,
nil_ //!< Safe, nil_ is dereferencable
>;
//! defer_i alias template for F<T, Is...>
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
detail::is_applicable_i_<T, F, Is...>,
detail::defer_i_<T, F, Is...>,
nil_ //!< Safe, nil_ is dereferencable
>;
//! @}
//! quote
//! @{
/*!
* quote is a higher-order primitive that wraps an n-ary Metafunction
* to create a corresponding Metafunction Class (Invocable).
* 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 <template <typename...> class F>
struct quote {
template <typename... Args>
using apply = eval<
defer<F, Args...> //!< defer here to avoid DR1430
defer<F, Args...> //!< defer here to avoid DR1430
>;
};
//! Wrap a template \p F taking literals of type \p T into an Invokable
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
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...> //!< defer here to avoid DR1430
defer_i<T, F, Ts::type::value...> //!< 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 <typename Fn, typename... Args>
using invoke = typename Fn::template apply<Args...>;
/*!
* Evaluate the invocation of the nested apply metafunction from \p Fn
* with the arguments \p Args.
*/
template <typename Fn, typename... Args>
using invoke_t = eval< invoke <Fn, Args...>>;
//! @}
//! compose
//! @{
namespace detail {
template<typename ...Fns> struct compose_ { };
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>
@@ -228,7 +283,6 @@ namespace meta{
invoke<compose_<Fns...>, Args...>
>;
};
// Termination specialization, finally pass the arguments
template<typename Fn0>
struct compose_<Fn0> {
@@ -238,25 +292,40 @@ namespace meta{
}
/*!
* Create an invocable from other invocables by composition.
* 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.
* That because of the "return" type of metafunction. They can only return one
* 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<compose<F1, F2, F3>, int>,
* F1 <F2 <F3 <int>>>
* >, "" );
* static_assert( std::is_same<
* invoke<compose<quote<F1>, quote<F2>, quote<F3>>, int>, F1<F2<F3<int>>>
* >, "");
* \endcode
*/
template <typename... Fns>
using compose = detail::compose_<Fns...>;
/*!
* 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<compose_f<F1, F2, F3>, int>, F1 <F2 <F3 <int>>>
* >, "");
* \endcode
*/
template <template <typename...> class... Fns>
using compose_f = detail::compose_f_<Fns...>;
//! @}
/*!
* Applies the Invocable \p Fn by binding the arguments \p Ts
* Applies the invocable \p Fn by binding the arguments \p Ts
* to the front of \p Fn.
*/
template<typename Fn, typename... Ts>
@@ -275,18 +344,19 @@ namespace meta{
using apply = invoke<Fn, Us..., Ts...>;
};
/*
* ========== meta:: predicates ============
*/
template <typename T1>
struct same_as {
template < typename T2>
template <typename T2>
struct apply : same_<T1, T2> { };
};
template <typename T1>
struct not_same_as {
template < typename T2>
template <typename T2>
struct apply : not_same_<T1, T2> { };
};
-118
View File
@@ -1,118 +0,0 @@
/*!
* \file logical.h
* \brief Template meta-programming logic operator and type relations.
*
* Copyright (C) 2018-2019 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 details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_logical_h__
#define __utl_meta_logical_h__
#include <utl/core/impl.h>
#include <utl/meta/selection.h>
/*!
* \ingroup meta
* \defgroup logic
* logic operator and type relations support header
*/
//! @{
namespace utl {
namespace meta{
/*!
* Logical relation for types
*/
//! @{
//! Negate the *bool* constant parameter
template <bool B>
using not_c = bool_<!B>;
//! not
template<typename _Tp>
using not_ = not_c<_Tp::type::value>;
//! OR implementation
//! @{
namespace detail {
template<typename...> struct _or_;
template<>
struct _or_<> : false_ { };
template<typename _T1>
struct _or_<_T1> : _T1 { };
template<typename _T1, typename _T2>
struct _or_ <_T1, _T2>
: if_<_T1, _T1, _T2> { };
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
struct _or_<_T1, _T2, _T3, _Tn...>
: if_<_T1, _T1, _or_<_T2, _T3, _Tn...>> { };
}
template <typename... _Ts>
using or_ = eval<detail::_or_<_Ts...>>;
//! @}
//! AND implementation
//! @{
namespace detail {
template<typename...> struct _and_;
template<>
struct _and_<>
: true_ { };
template<typename _T1>
struct _and_ <_T1>
: _T1 { };
template<typename _T1, typename _T2>
struct _and_<_T1, _T2>
: if_<_T1, _T2, _T1> { };
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
struct _and_<_T1, _T2, _T3, _Tn...>
: if_<_T1, _and_<_T2, _T3, _Tn...>, _T1> { };
}
template <typename... _Ts>
using and_ = eval<detail::_and_<_Ts...>>;
//! @}
//! same
//! @{
template<typename _T1, typename _T2>
struct same_ : false_ { };
template<typename _Tp>
struct same_ <_Tp, _Tp> : true_ { };
//! @}
//! not same
//! @{
template<typename _T1, typename _T2>
using not_same_ = not_<eval<same_<_T1, _T2>>>;
//! @}
//! @}
}}
//! @}
#endif /* __utl_meta_logical_h__ */
+3 -4
View File
@@ -1,6 +1,6 @@
/*!
* \file /utl/core/version.h
* \brief version and cpp version checks
* \file /utl/meta/meta.h
* \brief Include all meta library
*
* Copyright (C) 2018-2019 Christos Choutouridis
*
@@ -22,11 +22,10 @@
#define __utl_meta_meta_h__
#include <utl/meta/integral.h>
#include <utl/meta/typelist.h>
#include <utl/meta/selection.h>
#include <utl/meta/logical.h>
#include <utl/meta/operations.h>
#include <utl/meta/useif.h>
#include <utl/meta/typelist.h>
#include <utl/meta/detection.h>
#include <utl/meta/invoke.h>
+105 -10
View File
@@ -1,6 +1,6 @@
/*!
* \file operators.h
* \brief Template meta-programming integral constant arithmetic
* \file operations.h
* \brief Integral constant operations and logical operations
*
* Copyright (C) 2018-2019 Christos Choutouridis
*
@@ -17,11 +17,105 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_arithmetic_h__
#define __utl_meta_arithmetic_h__
#ifndef __utl_meta_operations_h__
#define __utl_meta_operations_h__
#include <utl/core/impl.h>
#include <utl/meta/logical.h>
#include <utl/meta/selection.h>
/*!
* \ingroup meta
* \defgroup logic
* logic operators and type relations support
*/
//! @{
namespace utl {
namespace meta{
/*!
* Logical relation for types
*/
//! @{
//! Negate the *bool* constant parameter
template <bool B>
using not_c = bool_<!B>;
//! not
template<typename _Tp>
using not_ = not_c<_Tp::type::value>;
//! OR implementation
//! @{
namespace detail {
template<typename...> struct _or_;
template<>
struct _or_<> : false_ { };
template<typename _T1>
struct _or_<_T1> : _T1 { };
template<typename _T1, typename _T2>
struct _or_ <_T1, _T2>
: if_<_T1, _T1, _T2> { };
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
struct _or_<_T1, _T2, _T3, _Tn...>
: if_<_T1, _T1, _or_<_T2, _T3, _Tn...>> { };
}
template <typename... _Ts>
using or_ = eval<detail::_or_<_Ts...>>;
//! @}
//! AND implementation
//! @{
namespace detail {
template<typename...> struct _and_;
template<>
struct _and_<>
: true_ { };
template<typename _T1>
struct _and_ <_T1>
: _T1 { };
template<typename _T1, typename _T2>
struct _and_<_T1, _T2>
: if_<_T1, _T2, _T1> { };
template<typename _T1, typename _T2, typename _T3, typename... _Tn>
struct _and_<_T1, _T2, _T3, _Tn...>
: if_<_T1, _and_<_T2, _T3, _Tn...>, _T1> { };
}
template <typename... _Ts>
using and_ = eval<detail::_and_<_Ts...>>;
//! @}
//! same
//! @{
template<typename _T1, typename _T2>
struct same_ : false_ { };
template<typename _Tp>
struct same_ <_Tp, _Tp> : true_ { };
//! @}
//! not same
//! @{
template<typename _T1, typename _T2>
using not_same_ = not_<eval<same_<_T1, _T2>>>;
//! @}
//! @}
}}
//! @}
/*!
* \ingroup meta
@@ -33,10 +127,10 @@
namespace utl {
namespace meta {
/*!
* Math operations
* requires IntegralConstant(_Tp)
*/
/*!
* Math operations
* requires IntegralConstant(_Tp)
*/
//! @{
//! Negation
@@ -129,4 +223,5 @@ namespace meta {
}}
//!@}
#endif /* __utl_meta_integral_h__ */
#endif /* __utl_meta_operations_h__ */
+3 -9
View File
@@ -22,7 +22,6 @@
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/sfinae.h>
/*!
* \ingroup meta
@@ -74,15 +73,10 @@ namespace meta{
//! @{
//! Select the first type of a type sequence
template <typename T1, typename ...>
struct first_of {
using type = T1;
};
template <typename T1, typename ...> using first_of = T1;
//! Select the second type of a type sequence
template <typename T1, typename T2, typename ...>
struct second_of {
using type = T2;
};
template <typename T1, typename T2, typename ...> using second_of = T2;
//! @}
}}
+15 -29
View File
@@ -21,6 +21,7 @@
#define __utl_meta_sfinae_h__
#include <utl/core/impl.h>
#include <type_traits>
/*!
* \ingroup meta
@@ -34,48 +35,33 @@ namespace meta {
//! Tool to enable a partial specialization only if a boolean condition is true.
//! @{
namespace detail {
template <typename... T>
struct dev_null { using type = dev_null; }; //< Same as typelist
// template <typename... T>
// struct dev_null { using type = dev_null; }; //< Same as typelist
template <bool If> struct when_ { };
template <> struct when_<true> { using type = void; };
}
//! Well formed only if \p If is true
template <bool If>
using when = eval<detail::when_<If>>;
using when = eval< detail::when_<If> >;
// //! Well formed only if all of \p Ifs are \c true
// template <bool ...Ifs>
// using when_all = detail::dev_null<
// when<Ifs>...
// >;
//! Well formed only if all of \p Ifs are \c true
template <bool ...Ifs>
using when_all = detail::dev_null<
when<Ifs>...
>;
//! @}
//! select _Tp if \p If is true, else SFINAE
//! We implement enable_if so we don't have to pull entire \c <type_traits> from stl
//! enable_if
//! @{
template <bool If, typename _Tp = void>
struct enable_if {
using type = _Tp;
};
template<typename _Tp>
struct enable_if <false, _Tp> { /* SFINAE*/ };
//! Alias template for enable_if
template <bool If, typename _Tp = void>
using use_if = enable_if<If, _Tp>;
//! enable_if, imported from stl
template <bool If, typename _Tp = void> using enable_if = std::enable_if<If, _Tp>;
//! Publicly recognized alias template for enable_if
template<bool If, typename _Tp = void>
using enable_if_t = eval<
enable_if<If, _Tp>
>;
//! alias template for enable_if
template<bool If, typename _Tp = void> using enable_if_t = eval< enable_if<If, _Tp> >;
//! Uniform alias template for use_if
template<bool If, typename _Tp = void>
using use_if_t = eval<
enable_if<If, _Tp>
>;
//! @}
}}
+67 -64
View File
@@ -17,12 +17,11 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __utl_meta_pack_h__
#define __utl_meta_pack_h__
#ifndef __utl_meta_typelist_h__
#define __utl_meta_typelist_h__
#include <utl/core/impl.h>
#include <utl/meta/integral.h>
#include <utl/meta/idx_sequence.h>
#include <utl/meta/detection.h>
#include <utl/meta/invoke.h>
#include <utl/meta/sfinae.h>
@@ -39,7 +38,7 @@ namespace meta {
* \brief
* A class template that just holds a parameter pack.
*
* The idea came from MPL's sequence concept[1] and from N4115[2].
* The idea came from MPL's sequence concept [\ref link1 1] and from N4115 [\ref link2 2].
* In addition to N4115's name "packer" we just prefer a name which is object, not a subject.
* This way the name gives the feeling of a container and smells like Python.
*
@@ -53,14 +52,14 @@ namespace meta {
* l1 a {};
* \endcode
*
* boost::hana[3] suggests a more powerful scheme were type invariant structures can be used
* boost::hana [\ref link3 3] suggests a more powerful scheme were type invariant structures can be used
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
* responsibility that comes along). So a simple python-like list with some extra vector-like
* element access functionalities and no iterators is good enough(for now).
*
* [1]: https://www.boost.org/doc/
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
* [3]: https://github.com/boostorg/hana
* \anchor link1 [1]: https://www.boost.org/doc/
* \anchor link2 [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
* \anchor link3 [3]: https://github.com/boostorg/hana
*/
template <typename... Ts>
struct typelist {
@@ -197,6 +196,9 @@ namespace meta {
template <typename Fn, typename Seq>
using apply = apply_impl::apply_<Fn, Seq>;
template <typename Fn, typename Seq>
using apply_t = eval <apply<Fn, Seq>>;
//! @}
/*
@@ -206,11 +208,8 @@ namespace meta {
//! @{
namespace at_impl {
template <typename T> struct _as_pointer__ { using type = T*; };
template <typename T> struct _as_pointer__<T*> { using type = T*; };
template <typename T> using as_pointer_ = eval<
_as_pointer__<T>
>;
template <typename T> struct _add_pointer { using type = T*; };
template <typename T> using add_pointer = eval < _add_pointer <T> >;
template <typename ...>
struct at_head_ { };
@@ -230,7 +229,7 @@ namespace meta {
struct at_<typelist<List...>, N> {
using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void*
using type = decltype(
head_::select(static_cast<as_pointer_<List>>(nullptr)...) //< pass all as List*...
head_::select(static_cast<add_pointer<List>>(nullptr)...) //< pass all as List*...
);
};
}
@@ -242,7 +241,7 @@ namespace meta {
*/
template <typename List, index_t N>
using at_c = eval<
at_impl::at_<List, N>
at_impl::at_<List, N>
>;
/*!
@@ -271,7 +270,7 @@ namespace meta {
//! Complexity \f$ O(1) \f$.
template <typename List>
using front = eval<
front_impl::front_<List>
front_impl::front_<List>
>;
//! @}
@@ -284,7 +283,7 @@ namespace meta {
template <typename Head, typename... Tail>
struct back_<typelist<Head, Tail...>> {
using type = at_c <
typelist<Head, Tail...>, sizeof...(Tail)
typelist<Head, Tail...>, sizeof...(Tail)
>;
};
}
@@ -293,7 +292,7 @@ namespace meta {
//! Complexity \f$ O(N) \f$.
template <typename List>
using back = eval<
back_impl::back_<List>
back_impl::back_<List>
>;
//! @}
/*
@@ -335,7 +334,7 @@ namespace meta {
*/
template <typename... Lists>
using cat = eval<
cat_impl::cat_<Lists...>
cat_impl::cat_<Lists...>
>;
//! @}
@@ -435,7 +434,7 @@ namespace meta {
*/
template <typename List, typename V, typename Fn>
using rev_fold = eval<
rev_fold_impl::rev_fold_<List, V, Fn>
rev_fold_impl::rev_fold_<List, V, Fn>
>;
//! @}
@@ -464,7 +463,6 @@ namespace meta {
//! reverse
//! @{
namespace reverse_impl {
template <typename List, typename V = typelist<>>
struct reverse_ {
using type = fold<List, V, quote<push_front>>;
@@ -477,7 +475,7 @@ namespace meta {
*/
template <typename List>
using reverse = eval<
reverse_impl::reverse_<List>
reverse_impl::reverse_<List>
>;
//! @}
@@ -500,7 +498,7 @@ namespace meta {
*/
template <typename List>
using pop_front = eval<
pop_front_impl::pop_front_<List>
pop_front_impl::pop_front_<List>
>;
//! @}
@@ -524,7 +522,7 @@ namespace meta {
*/
template <typename List>
using pop_back = eval <
pop_back_impl::pop_back_<List>
pop_back_impl::pop_back_<List>
>;
//! @}
@@ -538,7 +536,7 @@ namespace meta {
struct transform_<typelist<typelist<Ts...>, Fn>,
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
using type = typelist<
invoke_t<Fn, Ts>...
invoke_t<Fn, Ts>...
>;
};
@@ -546,7 +544,7 @@ namespace meta {
struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
using type = typelist<
invoke_t<Fn, Ts0, Ts1>...
invoke_t<Fn, Ts0, Ts1>...
>;
};
}
@@ -559,14 +557,14 @@ namespace meta {
* \example
* \code
* using l1 = typelist<char, int, ...>;
* using l2 = typelist<void, void, ...>;
* using l2 = typelist<void, double, ...>;
* using r1 = transform<l1, F1>; // F1, unary invocable
* using r2 = transform<l1, l2, F2>; // F2, binary invocable
* \endcode
*/
template <typename... Args>
using transform = eval<
transform_impl::transform_<typelist<Args...>>
transform_impl::transform_<typelist<Args...>>
>;
//! @}
@@ -581,7 +579,7 @@ namespace meta {
struct transform_lazy_<typelist<typelist<Ts...>, Fn>,
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
using type = typelist<
invoke<Fn, Ts>...
invoke<Fn, Ts>...
>;
};
@@ -590,7 +588,7 @@ namespace meta {
struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
using type = typelist<
invoke<Fn, Ts0, Ts1>...
invoke<Fn, Ts0, Ts1>...
>;
};
}
@@ -612,7 +610,7 @@ namespace meta {
*/
template <typename... Args>
using transform_lazy = eval<
transform_lazy_impl::transform_lazy_<typelist<Args...>>
transform_lazy_impl::transform_lazy_<typelist<Args...>>
>;
//! @}
@@ -627,11 +625,11 @@ namespace meta {
struct find_if_<typelist<Head, Tail...>, Fn, N> {
// Recursive call to find_if_ until Fn returns true_
using type = if_ <
invoke_t<Fn, Head>,
index_<N>, // done, return current index
eval<find_if_< // not done, re-call find_if_ with the Tail...
typelist<Tail...>, Fn, N+1>
>
invoke_t<Fn, Head>,
index_<N>, // done, return current index
eval<find_if_< // not done, re-call find_if_ with the Tail...
typelist<Tail...>, Fn, N+1>
>
>;
};
@@ -655,7 +653,7 @@ namespace meta {
*/
template<typename List, typename Pred>
using find_if = eval<
find_if_impl::find_if_<List, Pred, 0>
find_if_impl::find_if_<List, Pred, 0>
>;
/*!
@@ -675,11 +673,11 @@ namespace meta {
struct seek_if_<typelist<Head, Tail...>, Fn, N> {
// recursive call to seek_if_ until Fn returns true_
using type = if_ <
invoke_t<Fn, Head>,
typelist<Head, Tail...>, // done, return the typelist starting from here
eval<seek_if_< // not done, re-call seek_if_ with the Tail...
typelist<Tail...>, Fn, N+1>
>
invoke_t<Fn, Head>,
typelist<Head, Tail...>, // done, return the typelist starting from here
eval<seek_if_< // not done, re-call seek_if_ with the Tail...
typelist<Tail...>, Fn, N+1>
>
>;
};
@@ -703,7 +701,7 @@ namespace meta {
*/
template <typename List, typename Pred>
using seek_if = eval<
seek_if_impl::seek_if_<List, Pred, 0>
seek_if_impl::seek_if_<List, Pred, 0>
>;
/*!
* Search for the first \c Item on the \p List of type \p T and return the rest
@@ -724,13 +722,13 @@ namespace meta {
// Recursive call to count_if_ up to the end of List, counting all invokes of Fn
// returning true_
using type = if_ <
invoke_t<Fn, Head>,
eval<
count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
>,
eval<
count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
>
invoke_t<Fn, Head>,
eval<
count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
>,
eval<
count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
>
>;
};
@@ -753,7 +751,7 @@ namespace meta {
*/
template <typename List, typename Pred>
using count_if = eval<
count_if_impl::count_if_<List, Pred, 0>
count_if_impl::count_if_<List, Pred, 0>
>;
/*!
@@ -774,9 +772,9 @@ namespace meta {
// Recursive call to filter_ up to the end of the List, creating a new list
// of items for which the invoke of Fn returns true_
using type = if_ <
invoke_t <Fn, Head>,
eval<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
eval<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
invoke_t <Fn, Head>,
eval<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
eval<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
>;
};
@@ -798,7 +796,7 @@ namespace meta {
*/
template <typename List, typename Pred>
using filter = eval<
filter_impl::filter_<List, Pred, typelist<>>
filter_impl::filter_<List, Pred, typelist<>>
>;
//! @}
@@ -813,9 +811,9 @@ namespace meta {
// Recursive call to replace_if_ up to the end of the List, creating a new list
// of items based on invocation of Fn
using type = if_ <
invoke_t<Fn, Head>,
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
invoke_t<Fn, Head>,
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
>;
};
@@ -839,14 +837,14 @@ namespace meta {
*/
template<typename List, typename Pred, typename T>
using replace_if = eval<
replace_if_impl::replace_if_<List, Pred, T, typelist<>>
replace_if_impl::replace_if_<List, Pred, T, typelist<>>
>;
//! Alias wrapper that returns a new \c typelist where all instances of type \p T have
//! been replaced with \p U.
template <typename List, typename T, typename U>
using replace = eval <
replace_if <List, same_as<T>, U>
replace_if <List, same_as<T>, U>
>;
//! @}
@@ -854,25 +852,30 @@ namespace meta {
//! Returns \c true_ if \p Pred returns \c true_ for all the elements in the \p List or if the
//! \p List is empty and \c false_ otherwise.
template <typename List, typename Pred>
using all_of = empty<
using all_of = if_ <
empty <List>,
false_,
empty <
filter <List, compose<quote<not_>, Pred>>
>
>;
//! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List
//! and \c false_ otherwise.
template <typename List, typename Pred>
using any_of = not_<
empty<filter <List, Pred>>
empty<filter <List, Pred>>
>;
//! Returns \c true_ if \p Pred returns \c false_ for all the elements in the \p List
//! or if the \p List is empty and \c false otherwise.
template <typename List, typename Pred>
using none_of = empty<
filter <List, Pred>
filter <List, Pred>
>;
}}
//! @}
#endif /* __utl_meta_pack_h__ */
#endif /* __utl_meta_typelist_h__ */
+11 -19
View File
@@ -21,7 +21,7 @@
#define __utl_meta_useif_h__
#include <utl/core/impl.h>
#include <utl/meta/logical.h>
#include <utl/meta/operations.h>
#include <utl/meta/sfinae.h>
/*!
@@ -35,32 +35,24 @@ namespace meta {
//! If same type resolves to _Ret, else SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_same_t = eval<
enable_if<
same_<_T1, _T2>::value, _Ret
>
using use_if_same_t = enable_if_t<
same_<_T1, _T2>::value, _Ret
>;
//! If not same type resolves to _Ret, else SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_not_same_t = eval<
enable_if<
!same_<_T1, _T2>::value, _Ret
>
using use_if_not_same_t = enable_if_t<
!same_<_T1, _T2>::value, _Ret
>;
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_any_t = eval<
enable_if<
or_<_T1, _T2>::value, _Ret
>
template <typename T1, typename... Ts>
using use_if_any_t = enable_if_t<
or_<T1, Ts...>::value, T1
>;
//! If both type (_T1 and _T2) type resolves to _Ret, else to SFINAE
template <typename _T1, typename _T2, typename _Ret =_T1>
using use_if_both_t = eval<
enable_if<
and_<_T1, _T2>::value, _Ret
>
template <typename T1, typename... Ts>
using use_if_all_t = enable_if_t<
and_<T1, Ts...>::value, T1
>;
}}
+1 -2
View File
@@ -1,6 +1,6 @@
/*!
* \file utl/utility/invoke.h
* \brief invoke() and invoke() traits implementation
* \brief invoke() and invoke traits implementation
*
* Copyright (C) 2018-2019 Christos Choutouridis
*
@@ -30,7 +30,6 @@
/*!
* \ingroup utility
* \defgroup invoke
*
*/
//! @{
namespace utl {