diff --git a/include/utl/com/_1wire.h b/include/utl/com/_1wire.h index d7e47f0..58478e7 100644 --- a/include/utl/com/_1wire.h +++ b/include/utl/com/_1wire.h @@ -689,17 +689,18 @@ namespace _1wire_i_det { meta::void_t < // typename _Tp::Speed, // typename _Tp::Command, - meta::use_if_same_t , bool>, - meta::use_if_same_t , byte_t>, - //meta::use_if_same_t , size_t>, - meta::use_if_same_t , byte_t>, - //meta::use_if_same_t , size_t>, - meta::use_if_same_t , void>, - meta::use_if_same_t , void>, - meta::use_if_same_t , void>, - meta::use_if_same_t , void>, - meta::use_if_same_t , _1wire_id_t>, - meta::use_if_same_t , _1wire_id_t> +// meta::use_if_same_t , bool>, +// meta::use_if_same_t , byte_t>, +// //meta::use_if_same_t , size_t>, +// meta::use_if_same_t , byte_t>, +// //meta::use_if_same_t , size_t>, +// meta::use_if_same_t , void>, +// meta::use_if_same_t , void>, +// meta::use_if_same_t , void>, +// meta::use_if_same_t , void>, +// meta::use_if_same_t , _1wire_id_t>, +// meta::use_if_same_t , _1wire_id_t> + void > //!^ SFINAE may apply > : meta::true_ {}; } // namespace _1wire_i_det diff --git a/include/utl/com/i2c.h b/include/utl/com/i2c.h index 948f5ba..560cd56 100644 --- a/include/utl/com/i2c.h +++ b/include/utl/com/i2c.h @@ -261,12 +261,13 @@ namespace utl { struct is_i2c_ <_Tp, meta::void_t < typename _Tp::Sequence, - meta::use_if_same_t >, - meta::use_if_same_t >, - meta::use_if_same_t >, - meta::use_if_same_t >, - meta::use_if_same_t >, - meta::use_if_same_t > +// meta::use_if_same_t >, +// meta::use_if_same_t >, +// meta::use_if_same_t >, +// meta::use_if_same_t >, +// meta::use_if_same_t >, +// meta::use_if_same_t > + void > > : meta::true_ { }; } diff --git a/include/utl/com/spi_bb.h b/include/utl/com/spi_bb.h index 45bacce..16954c7 100644 --- a/include/utl/com/spi_bb.h +++ b/include/utl/com/spi_bb.h @@ -75,9 +75,9 @@ namespace utl { //! \name SPI implementation specific functions //!@{ template 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 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 static constexpr bool clkHigh () { return !static_cast(C); } @@ -113,9 +113,9 @@ namespace utl { byte_t _tx_data (byte_t out) { return _tx_data_impl (out); } template - 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 - 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 template - meta::use_if_t <(C == spi::cpha::LOW), byte_t> + meta::enable_if_t <(C == spi::cpha::LOW), byte_t> spi_bb_i::_tx_data_impl (byte_t out) { byte_t in {}; SCLK (clkL_); @@ -158,7 +158,7 @@ namespace utl { */ template template - meta::use_if_t <(C == spi::cpha::HIGH), byte_t> + meta::enable_if_t <(C == spi::cpha::HIGH), byte_t> spi_bb_i::_tx_data_impl (byte_t out) { byte_t in {}; SCLK (clkL_); @@ -207,9 +207,9 @@ namespace utl { //! \name SPI implementation specific functions //!@{ template 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 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 static constexpr bool clkHigh () { return !static_cast(C); } @@ -241,9 +241,9 @@ namespace utl { byte_t _tx_data (byte_t out) final { return _tx_data_impl (out); } template - 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 - 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 template - meta::use_if_t <(C == spi::cpha::LOW), byte_t> + meta::enable_if_t <(C == spi::cpha::LOW), byte_t> spi_bb_i::_tx_data_impl (byte_t out) { byte_t in {}; SCLK (clkL_); @@ -286,7 +286,7 @@ namespace utl { */ template template - meta::use_if_t <(C == spi::cpha::HIGH), byte_t> + meta::enable_if_t <(C == spi::cpha::HIGH), byte_t> spi_bb_i::_tx_data_impl (byte_t out) { byte_t in {}; SCLK (clkL_); diff --git a/include/utl/concepts/stl.h b/include/utl/concepts/stl.h index 6b4d445..8cc7cf5 100644 --- a/include/utl/concepts/stl.h +++ b/include/utl/concepts/stl.h @@ -47,6 +47,14 @@ namespace utl { template using _ref_t = std::add_lvalue_reference_t; + template + 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 using try_op_not_ = decltype(!std::declval>()); +// template using try_op_eq_ = decltype(std::declval>() == std::declval>()); +// template using try_op_neq_ = decltype(std::declval>() != std::declval>()); +// template using try_op_and_ = decltype(std::declval>() && std::declval>()); +// template using try_op_or_ = decltype(std::declval>() || std::declval>()); +// +// template +// struct is_boolean__ { +// using type = meta::and_ < +// meta::is_detected, +// meta::is_detected, +// meta::is_detected, +// meta::is_detected, +// meta::is_detected +// >; +// }; + template struct is_boolean_ { using type = meta::false_; diff --git a/include/utl/dev/dev_iterators.h b/include/utl/dev/dev_iterators.h index 32aafb7..f24cf14 100644 --- a/include/utl/dev/dev_iterators.h +++ b/include/utl/dev/dev_iterators.h @@ -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_ {}; } diff --git a/include/utl/meta/detection.h b/include/utl/meta/detection.h index 4135b5f..6356a53 100644 --- a/include/utl/meta/detection.h +++ b/include/utl/meta/detection.h @@ -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 -#include +#include #include /*! @@ -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() = declval() ); + * template< class T > using copy_assign_t = decltype( declval() = declval() ); * - * 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 class Op, typename... Args> @@ -121,41 +120,115 @@ namespace meta { //! Detection predicate template< template class Op, typename... Args> constexpr bool is_detected_v = is_detected::value; - //! @} /*! - * Detection idiom toolkit + * Detection tool that evaluates to Op 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 if is well formed + * \arg nat_ if Op is ill formed + * \example + * \code + * template using try_type = typename T::type; // detector + * template using try_ppT = decltype (++(std::declval())); // detector + * static_assert( std::is_same> >(), ""); // detection failed + * static_assert( std::is_same&, detected_t> >(), ""); // detection succeed + * + * // if mFun is well formed + * static_assert(std::is_same< mFun, detected_t >(), ""); + * \endcode */ - //! @{ - - //! evaluates to evaluation of Op if it's valid and to nat_ if not template class Op, typename... Args> using detected_t = eval < detail::detector >; - //! evaluates to evaluation of Op if it's valid and to \p Default if not + /*! + * Detection tool that evaluates to Op 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 if is well formed + * \arg Default if Op is ill formed + * \example + * \code + * template using try_type = typename T::type; // detector + * template using try_ppT = decltype (++(std::declval())); // detector + * static_assert( std::is_same> >(), ""); // detection failed + * static_assert( std::is_same&, detected_or_t> >(), ""); // detection succeed + * + * // if mFun is well formed + * static_assert(std::is_same< mFun, detected_or_t >(), ""); + * \endcode + */ template class Op, typename... Args> using detected_or_t = eval < detail::detected_or >; - //! evaluates to true_ if evaluation of Op is \p Expected and to false_ if not + /*! + * Detection tool that evaluates to true_ if evaluation of Op + * 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 is well formed and evaluate to Expected + * \arg false_ Any other case + * \example + * \code + * template using try_type = typename T::type; // detector + * template using try_ppT = decltype (++(std::declval())); // detector + * static_assert( std::is_same> >(), ""); // detection failed + * static_assert( std::is_same&, try_ppT, A> >(), ""); // detection succeed + * + * // if mFun is well formed + * static_assert(std::is_same< true_, is_detected_exact, mFun, int, int> >(), ""); + * \endcode + */ template class Op, typename... Args > - using is_detected_exact = same_ >; + using is_detected_exact = eval < + same_> + >; //! evaluates to true if evaluation of Op is \p Expected and to false if not template class Op, typename... Args > constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value; - //! evaluates to true_ if evaluation of Op is convertible to \p To - //! and to false_ if not + /*! + * Detection tool that evaluates to true_ if evaluation of Op 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 is well formed and convertible to To + * \arg false_ Any other case + * \example + * \code + * template using try_type = typename T::type; // detector + * template using try_ppT = decltype (++(std::declval())); // detector + * static_assert( std::is_same> >(), ""); // detection failed + * static_assert( std::is_same&&, try_ppT, A> >(), "");// detection succeed + * + * // if mFun is well formed but not convertible to Foo + * static_assert(std::is_same< false_, is_detected_convertible >(), ""); + * \endcode + */ template class Op, typename... Args > - using is_detected_convertible = std::is_convertible< detected_t, To >; + using is_detected_convertible = eval < + std::is_convertible< detected_t, To > + >; //! evaluates to true if evaluation of Op is convertible to \p To //! and to false if not diff --git a/include/utl/meta/idx_sequence.h b/include/utl/meta/idx_sequence.h deleted file mode 100644 index 12bf3ba..0000000 --- a/include/utl/meta/idx_sequence.h +++ /dev/null @@ -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 . - */ -#ifndef __utl_meta_idx_sequence_h__ -#define __utl_meta_idx_sequence_h__ - -#include -#include - - -/*! - * \ingroup meta - * \defgroup index_sequence - */ -//! @{ - -namespace utl { -namespace meta { - - /*! - * Class template integer_sequence - */ - template - struct integer_sequence { - using value_type = _Tp; - static constexpr size_t size() noexcept { - return sizeof...(_Idx); - } - }; - - //! Alias template index_sequence - template - using index_sequence = integer_sequence; - - //! make_integer_sequence - //! @{ - namespace detail { - // Stores a tuple of indices - template struct index_tuple { }; - - // Concatenates two index_tuples. - template struct it_cat_; - - template - struct it_cat_ , index_tuple> { - using type = index_tuple; - }; - - // Builds an index_tuple<0, 1, 2, ..., _Num-1>. - template - struct make_index_tuple_ - : it_cat_>, - eval>> - { }; - // 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>> - struct make_integer_sequence_; - - template - 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 - using make_integer_sequence = eval>; - - //! Alias template make_index_sequence - //! Complexity \f$ O(log N) \f$ - template - using make_index_sequence = make_integer_sequence; - - //! Alias template index_sequence_for - //! Complexity \f$ O(log N) \f$ - //! where N is sizeof...(_Ts) - template - using index_sequence_for = make_index_sequence; - //! @} - -}} -//! @} -#endif /* __utl_meta_idx_sequence_h__ */ diff --git a/include/utl/meta/integral.h b/include/utl/meta/integral.h index 1301074..efc63a8 100644 --- a/include/utl/meta/integral.h +++ b/include/utl/meta/integral.h @@ -21,7 +21,8 @@ #define __utl_meta_integralconstant_h__ #include - +#include +#include /*! * \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 - using eval = typename _Tp::type; + //! Type alias for \p Tp::type. Used to evaluate/extract return type of metafunctions + template + 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 - 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 - constexpr _Tp integral_<_Tp, _v>::value; + template + using integral_ = std::integral_constant; //! @} //! Wrappers for basic types //! @{ //! bool_ type: integral constant wrapper for bool - template - using bool_ = integral_; + template + using bool_ = integral_; using true_ = bool_; //!< The type used as a compile-time boolean with true value. using false_ = bool_; //!< The type used as a compile-time boolean with false value. //! int8_ type: integral constant wrapper for \c int8_t - template - using int8_ = integral_; + template + using int8_ = integral_; //! uint8_ type: integral constant wrapper for \c uint8_t - template - using uint8_ = integral_; + template + using uint8_ = integral_; //! int16_ type: integral constant wrapper for \c int16_t - template - using int16_ = integral_; + template + using int16_ = integral_; //! uint16_ type: integral constant wrapper for \c uint16_t - template - using uint16_ = integral_; + template + using uint16_ = integral_; //! int32_ type: integral constant wrapper for \c int32_t - template - using int32_ = integral_; + template + using int32_ = integral_; //! uint32_ type: integral constant wrapper for \c uint32_t - template - using uint32_ = integral_; + template + using uint32_ = integral_; //! char_ type: integral constant wrapper for \c char - template - using char_ = integral_; + template + using char_ = integral_; //! int_ type: integral constant wrapper for \c int - template - using int_ = integral_; + template + using int_ = integral_; //! long_ type: integral constant wrapper for \c long - template - using long_ = integral_; + template + using long_ = integral_; //! index_ type: integral constant wrapper for \c index_t a.k.a std::size_t - template - using index_ = integral_; + template + using index_ = integral_; //! size_ type: integral constant wrapper for \c size_t a.k.a std::size_t - template - using size_ = integral_; + template + using size_ = integral_; - //! Computes the size of the type \p _Tp. + //! Computes the size of the type \p Tp. //! Complexity \f$ O(1) \f$. - template - using sizeof_ = size_; + template + using sizeof_ = size_; - //! 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 - using alignof_ = size_; + template + using alignof_ = size_; //! @} //! The last position we can express for indexing using Npos = size_; + //! integer sequence + //! @{ + template< class Tp, Tp... Ints > + using integer_sequence = std::integer_sequence; + + template + using make_integer_sequence = std::make_integer_sequence; + + //! Alias template index_sequence + template + using index_sequence = integer_sequence; + + //! Alias template make_index_sequence + template + using make_index_sequence = make_integer_sequence ; + + //! Alias template index_sequence_for + template + using index_sequence_for = make_index_sequence; + + //! @} }} + //!@} #endif /* __utl_meta_integralconstant_h__ */ diff --git a/include/utl/meta/invoke.h b/include/utl/meta/invoke.h index 586d18d..5c58f27 100644 --- a/include/utl/meta/invoke.h +++ b/include/utl/meta/invoke.h @@ -23,8 +23,7 @@ #include #include #include -#include -#include +#include /*! * \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 @@ -56,7 +59,7 @@ namespace meta{ #else template 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>; //! @} + /*! + * 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