@@ -689,17 +689,18 @@ namespace _1wire_i_det { | |||||
meta::void_t < | meta::void_t < | ||||
// typename _Tp::Speed, | // typename _Tp::Speed, | ||||
// typename _Tp::Command, | // 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 | > //!^ SFINAE may apply | ||||
> : meta::true_ {}; | > : meta::true_ {}; | ||||
} // namespace _1wire_i_det | } // namespace _1wire_i_det | ||||
@@ -261,12 +261,13 @@ namespace utl { | |||||
struct is_i2c_ <_Tp, | struct is_i2c_ <_Tp, | ||||
meta::void_t < | meta::void_t < | ||||
typename _Tp::Sequence, | 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_ { }; | > : meta::true_ { }; | ||||
} | } | ||||
@@ -75,9 +75,9 @@ namespace utl { | |||||
//! \name SPI implementation specific functions | //! \name SPI implementation specific functions | ||||
//!@{ | //!@{ | ||||
template <spi::bitOrder B =BitOrder> constexpr | 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 | 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 () { | template <spi::cpol C =CPOL> static constexpr bool clkHigh () { | ||||
return !static_cast<bool>(C); | return !static_cast<bool>(C); | ||||
} | } | ||||
@@ -113,9 +113,9 @@ namespace utl { | |||||
byte_t _tx_data (byte_t out) { return _tx_data_impl (out); } | byte_t _tx_data (byte_t out) { return _tx_data_impl (out); } | ||||
template <spi::cpha C =CPHA> | 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> | 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 | //! Data members | ||||
@@ -134,7 +134,7 @@ namespace utl { | |||||
*/ | */ | ||||
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | ||||
template <spi::cpha C> | 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) { | spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) { | ||||
byte_t in {}; | byte_t in {}; | ||||
SCLK (clkL_); | SCLK (clkL_); | ||||
@@ -158,7 +158,7 @@ namespace utl { | |||||
*/ | */ | ||||
template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | template <typename impl_t, spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | ||||
template <spi::cpha C> | 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) { | spi_bb_i<impl_t, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) { | ||||
byte_t in {}; | byte_t in {}; | ||||
SCLK (clkL_); | SCLK (clkL_); | ||||
@@ -207,9 +207,9 @@ namespace utl { | |||||
//! \name SPI implementation specific functions | //! \name SPI implementation specific functions | ||||
//!@{ | //!@{ | ||||
template <spi::bitOrder B =BitOrder> constexpr | 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 | 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 () { | template <spi::cpol C =CPOL> static constexpr bool clkHigh () { | ||||
return !static_cast<bool>(C); | return !static_cast<bool>(C); | ||||
} | } | ||||
@@ -241,9 +241,9 @@ namespace utl { | |||||
byte_t _tx_data (byte_t out) final { return _tx_data_impl (out); } | byte_t _tx_data (byte_t out) final { return _tx_data_impl (out); } | ||||
template <spi::cpha C =CPHA> | 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> | 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 | //! Data members | ||||
@@ -262,7 +262,7 @@ namespace utl { | |||||
*/ | */ | ||||
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | ||||
template <spi::cpha C> | 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) { | spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) { | ||||
byte_t in {}; | byte_t in {}; | ||||
SCLK (clkL_); | SCLK (clkL_); | ||||
@@ -286,7 +286,7 @@ namespace utl { | |||||
*/ | */ | ||||
template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | template <spi::cpol CPOL, spi::cpha CPHA, spi::bitOrder BitOrder> | ||||
template <spi::cpha C> | 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) { | spi_bb_i<virtual_tag, CPOL, CPHA, BitOrder>::_tx_data_impl (byte_t out) { | ||||
byte_t in {}; | byte_t in {}; | ||||
SCLK (clkL_); | SCLK (clkL_); | ||||
@@ -47,6 +47,14 @@ namespace utl { | |||||
template <typename T> | template <typename T> | ||||
using _ref_t = std::add_lvalue_reference_t<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 | * Same | ||||
*/ | */ | ||||
@@ -501,6 +509,23 @@ namespace utl { | |||||
}; | }; | ||||
#else | #else | ||||
namespace details { | 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> | template <typename B, typename = void> | ||||
struct is_boolean_ { | struct is_boolean_ { | ||||
using type = meta::false_; | using type = meta::false_; | ||||
@@ -425,10 +425,11 @@ namespace utl { | |||||
typename _Tp::difference_type, | typename _Tp::difference_type, | ||||
typename _Tp::pointer, | typename _Tp::pointer, | ||||
typename _Tp::reference, | 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_ {}; | > : meta::true_ {}; | ||||
} | } | ||||
@@ -702,10 +703,11 @@ namespace utl { | |||||
typename _Tp::difference_type, | typename _Tp::difference_type, | ||||
typename _Tp::pointer, | typename _Tp::pointer, | ||||
typename _Tp::reference, | 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_ {}; | > : meta::true_ {}; | ||||
} | } | ||||
@@ -986,10 +988,11 @@ namespace utl { | |||||
typename _Tp::difference_type, | typename _Tp::difference_type, | ||||
typename _Tp::pointer, | typename _Tp::pointer, | ||||
typename _Tp::reference, | 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_ {}; | > : meta::true_ {}; | ||||
} | } | ||||
@@ -1,8 +1,8 @@ | |||||
/*! | /*! | ||||
* \file detection.h | * \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 | * Copyright (C) 2018-2019 Christos Choutouridis | ||||
* | * | ||||
@@ -23,7 +23,7 @@ | |||||
#define __utl_meta_detection_h__ | #define __utl_meta_detection_h__ | ||||
#include <utl/core/impl.h> | #include <utl/core/impl.h> | ||||
#include <utl/meta/logical.h> | |||||
#include <utl/meta/operations.h> | |||||
#include <type_traits> | #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_ { | struct nat_ { | ||||
nat_() = delete; | nat_() = delete; | ||||
@@ -108,11 +109,9 @@ namespace meta { | |||||
* \example | * \example | ||||
* \code | * \code | ||||
* // archetypal alias for a copy assignment operation | * // 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 | * \endcode | ||||
*/ | */ | ||||
template <template<typename...> class Op, typename... Args> | template <template<typename...> class Op, typename... Args> | ||||
@@ -121,41 +120,115 @@ namespace meta { | |||||
//! Detection predicate | //! Detection predicate | ||||
template< template<typename...> class Op, typename... Args> | template< template<typename...> class Op, typename... Args> | ||||
constexpr bool is_detected_v = is_detected<Op, Args...>::value; | 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> | template <template<typename...> class Op, typename... Args> | ||||
using detected_t = eval < | using detected_t = eval < | ||||
detail::detector<nat_, void, Op, Args...> | 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 Default, | ||||
template<typename...> class Op, typename... Args> | template<typename...> class Op, typename... Args> | ||||
using detected_or_t = eval < | using detected_or_t = eval < | ||||
detail::detected_or<Default, Op, Args...> | 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 Expected, | ||||
template<typename...> class Op, typename... Args > | 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 | //! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not | ||||
template <typename Expected, | template <typename Expected, | ||||
template<typename...> class Op, typename... Args > | template<typename...> class Op, typename... Args > | ||||
constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value; | 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 To, | ||||
template<typename...> class Op, typename... Args > | 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 | //! evaluates to true if evaluation of Op<Args...> is convertible to \p To | ||||
//! and to false if not | //! and to false if not | ||||
@@ -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__ */ |
@@ -21,7 +21,8 @@ | |||||
#define __utl_meta_integralconstant_h__ | #define __utl_meta_integralconstant_h__ | ||||
#include <utl/core/impl.h> | #include <utl/core/impl.h> | ||||
#include <type_traits> | |||||
#include <utility> | |||||
/*! | /*! | ||||
* \ingroup meta | * \ingroup meta | ||||
@@ -43,9 +44,9 @@ namespace meta { | |||||
using type = nil_; | 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_ | ||||
//! Integral Constant is a holder class for a compile-time value of an integral type. | //! 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 | //! An integral constant object is implicitly convertible to the corresponding | ||||
//! run-time value of the wrapped integral type | //! 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 | //! Wrappers for basic types | ||||
//! @{ | //! @{ | ||||
//! bool_ type: integral constant wrapper for bool | //! 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 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. | using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value. | ||||
//! int8_ type: integral constant wrapper for \c int8_t | //! 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 | //! 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 | //! 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 | //! 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 | //! 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 | //! 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 | //! 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 | //! 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 | //! 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 | //! 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 | //! 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$. | //! 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$. | //! 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 | //! The last position we can express for indexing | ||||
using Npos = size_<index_t(-1)>; | 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__ */ | #endif /* __utl_meta_integralconstant_h__ */ |
@@ -23,8 +23,7 @@ | |||||
#include <utl/core/impl.h> | #include <utl/core/impl.h> | ||||
#include <utl/meta/integral.h> | #include <utl/meta/integral.h> | ||||
#include <utl/meta/detection.h> | #include <utl/meta/detection.h> | ||||
#include <utl/meta/selection.h> | |||||
#include <utl/meta/logical.h> | |||||
#include <utl/meta/operations.h> | |||||
/*! | /*! | ||||
* \ingroup meta | * \ingroup meta | ||||
@@ -36,15 +35,19 @@ namespace utl { | |||||
namespace meta{ | 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> | template <typename _Tp> | ||||
@@ -56,7 +59,7 @@ namespace meta{ | |||||
#else | #else | ||||
template <typename...> | template <typename...> | ||||
using apply = _Tp; //!< identity is invokable, must also have apply | using apply = _Tp; //!< identity is invokable, must also have apply | ||||
#endif | |||||
#endif | |||||
using type = _Tp; //!< identity | using type = _Tp; //!< identity | ||||
}; | }; | ||||
@@ -65,6 +68,49 @@ namespace meta{ | |||||
using identity_t = eval<identity<_Tp>>; | 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 | //! Is applicable trait | ||||
//! @{ | //! @{ | ||||
namespace detail { | namespace detail { | ||||
@@ -79,22 +125,29 @@ namespace meta{ | |||||
using type = decltype(check<F>(0)); | using type = decltype(check<F>(0)); | ||||
}; | }; | ||||
template <typename Fn, typename... Args> | |||||
using use_ = typename Fn::template apply<Args...>; | |||||
template<typename F, typename... T> | template<typename F, typename... T> | ||||
struct is_applicable_q_ { | 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...> | 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> | template<typename T, template <T...> class F, T... Is> | ||||
struct is_applicable_i_ { | 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 | static true_ check (int); //< Is... can be passed to G | ||||
template<typename TT, template<TT...> class G> | template<typename TT, template<TT...> class G> | ||||
static false_ check (...); //< all other combinations | static false_ check (...); //< all other combinations | ||||
@@ -106,26 +159,18 @@ namespace meta{ | |||||
//! check if we can instantiate \p F with parameters \p T | //! check if we can instantiate \p F with parameters \p T | ||||
template<template<typename...> class F, typename... T> | template<template<typename...> class F, typename... T> | ||||
using is_applicable_t = eval< | 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> | template<typename Q, typename... T> | ||||
using is_applicable_qt = eval < | 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 | //! check if we can instantiate \p F with parameters \p Is of type \p T | ||||
template <typename T, template<T...> class F, T... Is> | template <typename T, template<T...> class F, T... Is> | ||||
using is_applicable_it = eval< | 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> | //! template<template<typename...> class F, typename... Ts> | ||||
//! using defer_ = F<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 | //! In short, this is due to language's inability to expand Ts... into | ||||
//! a fixed parameter list of an alias template. | //! 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...> | //! defer alias template for F<Ts...> | ||||
template<template<class...> class F, class... Ts> | template<template<class...> class F, class... Ts> | ||||
using defer = if_< | 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...> | //! defer_i alias template for F<T, Is...> | ||||
template <typename T, template<T...> class F, T... Is> | template <typename T, template<T...> class F, T... Is> | ||||
using defer_i = if_ < | 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> | template <template <typename...> class F> | ||||
struct quote { | struct quote { | ||||
template <typename... Args> | template <typename... Args> | ||||
using apply = eval< | 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> | template <typename T, template <T...> class F> | ||||
struct quote_i { | struct quote_i { | ||||
// requires meta::Integral | // requires meta::Integral | ||||
template <typename... Ts> | template <typename... Ts> | ||||
using apply = eval< | 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 | //! compose | ||||
//! @{ | //! @{ | ||||
namespace detail { | 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 | // recursive call to all invokes | ||||
template<typename Fn0, typename ...Fns> | template<typename Fn0, typename ...Fns> | ||||
@@ -228,7 +283,6 @@ namespace meta{ | |||||
invoke<compose_<Fns...>, Args...> | invoke<compose_<Fns...>, Args...> | ||||
>; | >; | ||||
}; | }; | ||||
// Termination specialization, finally pass the arguments | // Termination specialization, finally pass the arguments | ||||
template<typename Fn0> | template<typename Fn0> | ||||
struct compose_<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 | * \note | ||||
* This implies from N invocables in \p Fns the first N-1 has to be unary. | * 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. | * type. So for n-ary invocables in the N-1 places the typelist<> is the solution. | ||||
* \example | * \example | ||||
* \code | * \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 | * \endcode | ||||
*/ | */ | ||||
template <typename... Fns> | template <typename... Fns> | ||||
using compose = detail::compose_<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. | * to the front of \p Fn. | ||||
*/ | */ | ||||
template<typename Fn, typename... Ts> | template<typename Fn, typename... Ts> | ||||
@@ -275,18 +344,19 @@ namespace meta{ | |||||
using apply = invoke<Fn, Us..., Ts...>; | using apply = invoke<Fn, Us..., Ts...>; | ||||
}; | }; | ||||
/* | /* | ||||
* ========== meta:: predicates ============ | * ========== meta:: predicates ============ | ||||
*/ | */ | ||||
template <typename T1> | template <typename T1> | ||||
struct same_as { | struct same_as { | ||||
template < typename T2> | |||||
template <typename T2> | |||||
struct apply : same_<T1, T2> { }; | struct apply : same_<T1, T2> { }; | ||||
}; | }; | ||||
template <typename T1> | template <typename T1> | ||||
struct not_same_as { | struct not_same_as { | ||||
template < typename T2> | |||||
template <typename T2> | |||||
struct apply : not_same_<T1, T2> { }; | struct apply : not_same_<T1, T2> { }; | ||||
}; | }; | ||||
@@ -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__ */ |
@@ -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 | * Copyright (C) 2018-2019 Christos Choutouridis | ||||
* | * | ||||
@@ -22,11 +22,10 @@ | |||||
#define __utl_meta_meta_h__ | #define __utl_meta_meta_h__ | ||||
#include <utl/meta/integral.h> | #include <utl/meta/integral.h> | ||||
#include <utl/meta/typelist.h> | |||||
#include <utl/meta/selection.h> | #include <utl/meta/selection.h> | ||||
#include <utl/meta/logical.h> | |||||
#include <utl/meta/operations.h> | #include <utl/meta/operations.h> | ||||
#include <utl/meta/useif.h> | #include <utl/meta/useif.h> | ||||
#include <utl/meta/typelist.h> | |||||
#include <utl/meta/detection.h> | #include <utl/meta/detection.h> | ||||
#include <utl/meta/invoke.h> | #include <utl/meta/invoke.h> | ||||
@@ -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 | * Copyright (C) 2018-2019 Christos Choutouridis | ||||
* | * | ||||
@@ -17,11 +17,105 @@ | |||||
* You should have received a copy of the GNU Lesser General Public License | * 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/>. | * 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/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 | * \ingroup meta | ||||
@@ -33,10 +127,10 @@ | |||||
namespace utl { | namespace utl { | ||||
namespace meta { | namespace meta { | ||||
/*! | |||||
* Math operations | |||||
* requires IntegralConstant(_Tp) | |||||
*/ | |||||
/*! | |||||
* Math operations | |||||
* requires IntegralConstant(_Tp) | |||||
*/ | |||||
//! @{ | //! @{ | ||||
//! Negation | //! Negation | ||||
@@ -129,4 +223,5 @@ namespace meta { | |||||
}} | }} | ||||
//!@} | //!@} | ||||
#endif /* __utl_meta_integral_h__ */ | |||||
#endif /* __utl_meta_operations_h__ */ |
@@ -22,7 +22,6 @@ | |||||
#include <utl/core/impl.h> | #include <utl/core/impl.h> | ||||
#include <utl/meta/integral.h> | #include <utl/meta/integral.h> | ||||
#include <utl/meta/sfinae.h> | |||||
/*! | /*! | ||||
* \ingroup meta | * \ingroup meta | ||||
@@ -74,15 +73,10 @@ namespace meta{ | |||||
//! @{ | //! @{ | ||||
//! Select the first type of a type sequence | //! 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 | //! 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; | |||||
//! @} | //! @} | ||||
}} | }} | ||||
@@ -21,6 +21,7 @@ | |||||
#define __utl_meta_sfinae_h__ | #define __utl_meta_sfinae_h__ | ||||
#include <utl/core/impl.h> | #include <utl/core/impl.h> | ||||
#include <type_traits> | |||||
/*! | /*! | ||||
* \ingroup meta | * \ingroup meta | ||||
@@ -34,48 +35,33 @@ namespace meta { | |||||
//! Tool to enable a partial specialization only if a boolean condition is true. | //! Tool to enable a partial specialization only if a boolean condition is true. | ||||
//! @{ | //! @{ | ||||
namespace detail { | 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 <bool If> struct when_ { }; | ||||
template <> struct when_<true> { using type = void; }; | template <> struct when_<true> { using type = void; }; | ||||
} | } | ||||
//! Well formed only if \p If is true | //! Well formed only if \p If is true | ||||
template <bool If> | 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> | |||||
>; | |||||
//! @} | //! @} | ||||
}} | }} | ||||
@@ -17,12 +17,11 @@ | |||||
* You should have received a copy of the GNU Lesser General Public License | * 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/>. | * 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/core/impl.h> | ||||
#include <utl/meta/integral.h> | #include <utl/meta/integral.h> | ||||
#include <utl/meta/idx_sequence.h> | |||||
#include <utl/meta/detection.h> | #include <utl/meta/detection.h> | ||||
#include <utl/meta/invoke.h> | #include <utl/meta/invoke.h> | ||||
#include <utl/meta/sfinae.h> | #include <utl/meta/sfinae.h> | ||||
@@ -39,7 +38,7 @@ namespace meta { | |||||
* \brief | * \brief | ||||
* A class template that just holds a parameter pack. | * 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. | * 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. | * This way the name gives the feeling of a container and smells like Python. | ||||
* | * | ||||
@@ -53,14 +52,14 @@ namespace meta { | |||||
* l1 a {}; | * l1 a {}; | ||||
* \endcode | * \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 | * 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 | * 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). | * 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> | template <typename... Ts> | ||||
struct typelist { | struct typelist { | ||||
@@ -197,6 +196,9 @@ namespace meta { | |||||
template <typename Fn, typename Seq> | template <typename Fn, typename Seq> | ||||
using apply = apply_impl::apply_<Fn, 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 { | 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 ...> | template <typename ...> | ||||
struct at_head_ { }; | struct at_head_ { }; | ||||
@@ -230,7 +229,7 @@ namespace meta { | |||||
struct at_<typelist<List...>, N> { | struct at_<typelist<List...>, N> { | ||||
using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void* | using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void* | ||||
using type = decltype( | 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> | template <typename List, index_t N> | ||||
using at_c = eval< | 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$. | //! Complexity \f$ O(1) \f$. | ||||
template <typename List> | template <typename List> | ||||
using front = eval< | using front = eval< | ||||
front_impl::front_<List> | |||||
front_impl::front_<List> | |||||
>; | >; | ||||
//! @} | //! @} | ||||
@@ -284,7 +283,7 @@ namespace meta { | |||||
template <typename Head, typename... Tail> | template <typename Head, typename... Tail> | ||||
struct back_<typelist<Head, Tail...>> { | struct back_<typelist<Head, Tail...>> { | ||||
using type = at_c < | 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$. | //! Complexity \f$ O(N) \f$. | ||||
template <typename List> | template <typename List> | ||||
using back = eval< | using back = eval< | ||||
back_impl::back_<List> | |||||
back_impl::back_<List> | |||||
>; | >; | ||||
//! @} | //! @} | ||||
/* | /* | ||||
@@ -335,7 +334,7 @@ namespace meta { | |||||
*/ | */ | ||||
template <typename... Lists> | template <typename... Lists> | ||||
using cat = eval< | using cat = eval< | ||||
cat_impl::cat_<Lists...> | |||||
cat_impl::cat_<Lists...> | |||||
>; | >; | ||||
//! @} | //! @} | ||||
@@ -435,7 +434,7 @@ namespace meta { | |||||
*/ | */ | ||||
template <typename List, typename V, typename Fn> | template <typename List, typename V, typename Fn> | ||||
using rev_fold = eval< | 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 | //! reverse | ||||
//! @{ | //! @{ | ||||
namespace reverse_impl { | namespace reverse_impl { | ||||
template <typename List, typename V = typelist<>> | template <typename List, typename V = typelist<>> | ||||
struct reverse_ { | struct reverse_ { | ||||
using type = fold<List, V, quote<push_front>>; | using type = fold<List, V, quote<push_front>>; | ||||
@@ -477,7 +475,7 @@ namespace meta { | |||||
*/ | */ | ||||
template <typename List> | template <typename List> | ||||
using reverse = eval< | using reverse = eval< | ||||
reverse_impl::reverse_<List> | |||||
reverse_impl::reverse_<List> | |||||
>; | >; | ||||
//! @} | //! @} | ||||
@@ -500,7 +498,7 @@ namespace meta { | |||||
*/ | */ | ||||
template <typename List> | template <typename List> | ||||
using pop_front = eval< | 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> | template <typename List> | ||||
using pop_back = eval < | 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>, | struct transform_<typelist<typelist<Ts...>, Fn>, | ||||
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ { | void_t<invoke<Fn, Ts>...> > /* SFINAE check */ { | ||||
using type = typelist< | 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>, | struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>, | ||||
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ { | void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ { | ||||
using type = typelist< | using type = typelist< | ||||
invoke_t<Fn, Ts0, Ts1>... | |||||
invoke_t<Fn, Ts0, Ts1>... | |||||
>; | >; | ||||
}; | }; | ||||
} | } | ||||
@@ -559,14 +557,14 @@ namespace meta { | |||||
* \example | * \example | ||||
* \code | * \code | ||||
* using l1 = typelist<char, int, ...>; | * using l1 = typelist<char, int, ...>; | ||||
* using l2 = typelist<void, void, ...>; | |||||
* using l2 = typelist<void, double, ...>; | |||||
* using r1 = transform<l1, F1>; // F1, unary invocable | * using r1 = transform<l1, F1>; // F1, unary invocable | ||||
* using r2 = transform<l1, l2, F2>; // F2, binary invocable | * using r2 = transform<l1, l2, F2>; // F2, binary invocable | ||||
* \endcode | * \endcode | ||||
*/ | */ | ||||
template <typename... Args> | template <typename... Args> | ||||
using transform = eval< | 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>, | struct transform_lazy_<typelist<typelist<Ts...>, Fn>, | ||||
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ { | void_t<invoke<Fn, Ts>...> > /* SFINAE check */ { | ||||
using type = typelist< | using type = typelist< | ||||
invoke<Fn, Ts>... | |||||
invoke<Fn, Ts>... | |||||
>; | >; | ||||
}; | }; | ||||
@@ -590,7 +588,7 @@ namespace meta { | |||||
struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>, | struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>, | ||||
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ { | void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ { | ||||
using type = typelist< | using type = typelist< | ||||
invoke<Fn, Ts0, Ts1>... | |||||
invoke<Fn, Ts0, Ts1>... | |||||
>; | >; | ||||
}; | }; | ||||
} | } | ||||
@@ -612,7 +610,7 @@ namespace meta { | |||||
*/ | */ | ||||
template <typename... Args> | template <typename... Args> | ||||
using transform_lazy = eval< | 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> { | struct find_if_<typelist<Head, Tail...>, Fn, N> { | ||||
// Recursive call to find_if_ until Fn returns true_ | // Recursive call to find_if_ until Fn returns true_ | ||||
using type = if_ < | 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> | template<typename List, typename Pred> | ||||
using find_if = eval< | 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> { | struct seek_if_<typelist<Head, Tail...>, Fn, N> { | ||||
// recursive call to seek_if_ until Fn returns true_ | // recursive call to seek_if_ until Fn returns true_ | ||||
using type = if_ < | 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> | template <typename List, typename Pred> | ||||
using seek_if = eval< | 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 | * 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 | // Recursive call to count_if_ up to the end of List, counting all invokes of Fn | ||||
// returning true_ | // returning true_ | ||||
using type = if_ < | 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> | template <typename List, typename Pred> | ||||
using count_if = eval< | 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 | // 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_ | // of items for which the invoke of Fn returns true_ | ||||
using type = if_ < | 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> | template <typename List, typename Pred> | ||||
using filter = eval< | 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 | // Recursive call to replace_if_ up to the end of the List, creating a new list | ||||
// of items based on invocation of Fn | // of items based on invocation of Fn | ||||
using type = if_ < | 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> | template<typename List, typename Pred, typename T> | ||||
using replace_if = eval< | 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 | //! Alias wrapper that returns a new \c typelist where all instances of type \p T have | ||||
//! been replaced with \p U. | //! been replaced with \p U. | ||||
template <typename List, typename T, typename U> | template <typename List, typename T, typename U> | ||||
using replace = eval < | 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 | //! 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. | //! \p List is empty and \c false_ otherwise. | ||||
template <typename List, typename Pred> | template <typename List, typename Pred> | ||||
using all_of = empty< | |||||
using all_of = if_ < | |||||
empty <List>, | |||||
false_, | |||||
empty < | |||||
filter <List, compose<quote<not_>, Pred>> | filter <List, compose<quote<not_>, Pred>> | ||||
> | |||||
>; | >; | ||||
//! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List | //! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List | ||||
//! and \c false_ otherwise. | //! and \c false_ otherwise. | ||||
template <typename List, typename Pred> | template <typename List, typename Pred> | ||||
using any_of = not_< | 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 | //! 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. | //! or if the \p List is empty and \c false otherwise. | ||||
template <typename List, typename Pred> | template <typename List, typename Pred> | ||||
using none_of = empty< | using none_of = empty< | ||||
filter <List, Pred> | |||||
filter <List, Pred> | |||||
>; | >; | ||||
}} | }} | ||||
//! @} | //! @} | ||||
#endif /* __utl_meta_pack_h__ */ | |||||
#endif /* __utl_meta_typelist_h__ */ |
@@ -21,7 +21,7 @@ | |||||
#define __utl_meta_useif_h__ | #define __utl_meta_useif_h__ | ||||
#include <utl/core/impl.h> | #include <utl/core/impl.h> | ||||
#include <utl/meta/logical.h> | |||||
#include <utl/meta/operations.h> | |||||
#include <utl/meta/sfinae.h> | #include <utl/meta/sfinae.h> | ||||
/*! | /*! | ||||
@@ -35,32 +35,24 @@ namespace meta { | |||||
//! If same type resolves to _Ret, else SFINAE | //! If same type resolves to _Ret, else SFINAE | ||||
template <typename _T1, typename _T2, typename _Ret =_T1> | 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 | //! If not same type resolves to _Ret, else SFINAE | ||||
template <typename _T1, typename _T2, typename _Ret =_T1> | 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 | //! 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 | //! 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,6 +1,6 @@ | |||||
/*! | /*! | ||||
* \file utl/utility/invoke.h | * \file utl/utility/invoke.h | ||||
* \brief invoke() and invoke() traits implementation | |||||
* \brief invoke() and invoke traits implementation | |||||
* | * | ||||
* Copyright (C) 2018-2019 Christos Choutouridis | * Copyright (C) 2018-2019 Christos Choutouridis | ||||
* | * | ||||
@@ -30,7 +30,6 @@ | |||||
/*! | /*! | ||||
* \ingroup utility | * \ingroup utility | ||||
* \defgroup invoke | * \defgroup invoke | ||||
* | |||||
*/ | */ | ||||
//! @{ | //! @{ | ||||
namespace utl { | namespace utl { | ||||
@@ -0,0 +1,218 @@ | |||||
/*! | |||||
* \file TmetaBasic.cpp | |||||
* | |||||
* 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 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/>. | |||||
* | |||||
*/ | |||||
#include <utl/meta/meta.h> | |||||
#include <gtest/gtest.h> | |||||
#include <type_traits> | |||||
namespace TmetaBasic { | |||||
using namespace utl; | |||||
using namespace meta; | |||||
/* | |||||
* Types to behave like Fixtures | |||||
*/ | |||||
// Test type_of fixture | |||||
template<class T> struct Identity { | |||||
using type = T; | |||||
}; | |||||
/* | |||||
* Test integral constant | |||||
*/ | |||||
TEST(TmetaBasic, IntegrealType) { | |||||
EXPECT_EQ(true, (std::is_same<int, eval<Identity<int>>>::value)); | |||||
EXPECT_EQ(true, (std::is_same<nil_, eval<nil_>>::value)); | |||||
EXPECT_EQ(true, (std::is_same<nil_, eval<eval<nil_>>>::value)); | |||||
EXPECT_EQ(true, (std::is_same<nil_, eval<eval<eval<nil_>>>>::value)); | |||||
} | |||||
TEST(TmetaBasic, IntegrealConstant) { | |||||
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::value_type>::value)); | |||||
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::type::value_type>::value)); | |||||
EXPECT_EQ(42, (integral_<int, 0>::value_type(42))); | |||||
EXPECT_EQ(42, (integral_<int, 42>())); | |||||
} | |||||
TEST(TmetaBasic, BasicTypes) { | |||||
EXPECT_EQ(true, (std::is_same<bool, bool_<false>::value_type>::value)); | |||||
EXPECT_EQ(true, bool_<true>::value); | |||||
EXPECT_EQ(true, (std::is_same<bool, false_::value_type>::value)); | |||||
EXPECT_EQ(false, false_::value); | |||||
EXPECT_EQ(true, (std::is_same<bool, true_::value_type>::value)); | |||||
EXPECT_EQ(true, true_::value); | |||||
EXPECT_EQ(true, (std::is_same<int8_t, int8_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int8_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<uint8_t, uint8_<0>::value_type>::value)); | |||||
EXPECT_EQ(42u, uint8_<42u>::value); | |||||
EXPECT_EQ(true, (std::is_same<int16_t, int16_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int16_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<uint16_t, uint16_<0>::value_type>::value)); | |||||
EXPECT_EQ(42u, uint16_<42u>::value); | |||||
EXPECT_EQ(true, (std::is_same<int32_t, int32_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int32_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<uint32_t, uint32_<0>::value_type>::value)); | |||||
EXPECT_EQ(42u, uint32_<42u>::value); | |||||
EXPECT_EQ(true, (std::is_same<char, char_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, char_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<int, int_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<long, long_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, long_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<index_t, index_<0>::value_type>::value)); | |||||
EXPECT_EQ(42U, index_<42U>::value); | |||||
EXPECT_EQ(true, (std::is_same<size_t, size_<0>::value_type>::value)); | |||||
EXPECT_EQ(42U, size_<42U>::value); | |||||
EXPECT_EQ(sizeof(int), sizeof_<int>::value); | |||||
EXPECT_EQ(alignof(int), alignof_<int>::value); | |||||
EXPECT_EQ(static_cast<index_t>(-1), Npos::value); | |||||
} | |||||
/* | |||||
* Test integral constant selection operations | |||||
*/ | |||||
TEST(TmetaBasic, Selection) { | |||||
struct Foo {}; | |||||
struct Bar {}; | |||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_c<true, int_<42>, false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<Foo, if_c<false, int_<42>, Foo>>())); | |||||
EXPECT_EQ (true, (std::is_same<Foo, if_c<42, Foo, Bar>>())); | |||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_<true_, int_<42>, Bar>>())); | |||||
EXPECT_EQ (true, (std::is_same<Bar, if_<false_, int_<42>, Bar>>())); | |||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_<int_<1>, int_<42>, Bar>>())); | |||||
EXPECT_EQ (true, (std::is_same<Foo, if_<int_<0>, int_<42>, Foo>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, first_of<true_, false_>>())); | |||||
EXPECT_EQ (false,(std::is_same<true_, first_of<false_, true_>>())); | |||||
EXPECT_EQ (false,(std::is_same<true_, second_of<true_, false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, second_of<false_, true_>>())); | |||||
} | |||||
TEST(TmetaBasic, LogicalOperations) { | |||||
struct Foo {}; | |||||
struct Bar {}; | |||||
EXPECT_EQ (true, (std::is_same<true_, not_c<false>>::value)); | |||||
EXPECT_EQ (true, (std::is_same<false_, not_c<true>>::value)); | |||||
EXPECT_EQ (true, (std::is_same<false_, not_c<1>>::value)); | |||||
EXPECT_EQ (true, (std::is_same<true_, not_c<0>>::value)); | |||||
EXPECT_EQ (true, (std::is_same<true_, not_<false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, not_<true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, not_<int_<0>>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, not_<int_<1>>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, or_<false_, false_, not_c<true>, int_<0>, not_<true_>>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, or_<>>())); | |||||
EXPECT_EQ (true, (std::is_same<int_<1>,or_<int_<1>>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, or_<true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, or_<false_, true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, or_<false_, false_, true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<int_<1>,or_<int_<0>, false_, not_<true_>, not_c<true>, int_<1>>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_, int_<1>, not_<false_>, not_c<false>>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, and_<>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, and_<false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, and_<true_, false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_, true_>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, and_<true_, true_, false_>>())); | |||||
EXPECT_EQ (true, (same_<Foo, Foo>())); | |||||
EXPECT_EQ (false, (same_<Foo, Bar>())); | |||||
EXPECT_EQ (true, (not_same_<Foo, Bar>())); | |||||
} | |||||
/* | |||||
* Test integral constant arithmetic operations | |||||
*/ | |||||
TEST(TmetaBasic, ArithmeticOperations) { | |||||
EXPECT_EQ (int_<42>(), inc<int_<41>>()); | |||||
EXPECT_EQ (int_<42>(), dec<int_<43>>()); | |||||
EXPECT_EQ (int_<42>(), (add<int_<23>, add<int_<17>, int_<2>>>())); | |||||
EXPECT_EQ (int_<42>(), (sub<int_<108>, int_<66>>())); | |||||
EXPECT_EQ (int_<42>(), (mult<int_<7>, mult<int_<3>, int_<2>>>())); | |||||
EXPECT_EQ (int_<42>(), (divide<int_<210>, int_<5>>())); | |||||
EXPECT_EQ (int_<42>(), negate<int_<-42>>()); | |||||
EXPECT_EQ (int_< 1>(), (modulo<int_<43>, int_<42>>())); | |||||
} | |||||
/* | |||||
* Test integral constant comparison operations | |||||
*/ | |||||
TEST(TmetaBasic, ComparisonOperations) { | |||||
EXPECT_EQ (true, (comp_eq<int_<7>, int_<7>>())); | |||||
EXPECT_EQ (false, (comp_eq<int_<42>, int_<7>>())); | |||||
EXPECT_EQ (true, (comp_ne<int_<42>, int_<7>>())); | |||||
EXPECT_EQ (false, (comp_ne<int_<42>, int_<42>>())); | |||||
EXPECT_EQ (true, (comp_lt<int_<42>, int_<43>>())); | |||||
EXPECT_EQ (false, (comp_lt<int_<43>, int_<42>>())); | |||||
EXPECT_EQ (true, (comp_gt<int_<43>, int_<42>>())); | |||||
EXPECT_EQ (false, (comp_gt<int_<42>, int_<43>>())); | |||||
EXPECT_EQ (true, (comp_le<int_<42>, int_<43>>())); | |||||
EXPECT_EQ (true, (comp_le<int_<42>, int_<42>>())); | |||||
EXPECT_EQ (false, (comp_le<int_<43>, int_<42>>())); | |||||
EXPECT_EQ (true, (comp_ge<int_<43>, int_<42>>())); | |||||
EXPECT_EQ (true, (comp_ge<int_<42>, int_<42>>())); | |||||
EXPECT_EQ (false, (comp_ge<int_<42>, int_<43>>())); | |||||
} | |||||
/* | |||||
* Test integral constant bit operations | |||||
*/ | |||||
TEST(TmetaBasic, BitOperations) { | |||||
EXPECT_EQ (0x00, (bitand_<uint8_<0x55>, uint8_<0xAA>>())); | |||||
EXPECT_EQ (0xFF, (bitor_ <uint8_<0x55>, uint8_<0xAA>>())); | |||||
EXPECT_EQ (0xFA, (bitxor_<uint8_<0x55>, uint8_<0xAF>>())); | |||||
EXPECT_EQ (0x00, (bitnot_<uint8_<-1>>())); | |||||
EXPECT_EQ (0x04, (shift_left<uint8_<0x01>, uint8_<2>>())); | |||||
EXPECT_EQ (0x00, (shift_left<uint8_<0x80>, uint8_<1>>())); | |||||
EXPECT_EQ (0x02, (shift_right<uint8_<0x08>, uint8_<2>>())); | |||||
EXPECT_EQ (0x00, (shift_right<uint8_<0x01>, uint8_<1>>())); | |||||
} | |||||
/* | |||||
* SFINAE | |||||
*/ | |||||
template <typename T, typename =when<same_<T, int>::type::value>> | |||||
int check (T x) { return x; } | |||||
int check (...) { return 0; } | |||||
TEST(TmetaBasic, Sfinae) { | |||||
EXPECT_EQ (42, check(42)); | |||||
EXPECT_EQ (0, check(42.0)); | |||||
EXPECT_EQ (0, check()); | |||||
// enable_if is imported so we trust stl and skip testing it | |||||
} | |||||
} |
@@ -0,0 +1,162 @@ | |||||
/*! | |||||
* \file TmetaDetection.cpp | |||||
* | |||||
* 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 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/>. | |||||
* | |||||
*/ | |||||
#include <utl/meta/meta.h> | |||||
#include <gtest/gtest.h> | |||||
#include <type_traits> | |||||
namespace TmetaDetection { | |||||
using namespace utl; | |||||
using namespace meta; | |||||
/* | |||||
* Types to behave like Fixtures | |||||
*/ | |||||
struct Foo {}; | |||||
struct Bar {}; | |||||
template <typename T> struct A { | |||||
using type = T; // nested type | |||||
A(int i, double d) : i_(i), d_(d) {} // declare a non-trivial constructor | |||||
A& operator++() { ++i_; return *this; } // declare an operator | |||||
// A sfinae function | |||||
template <typename TT = T, typename = when<std::is_integral<TT>::type::value>> | |||||
TT sfun () { return TT{}; } | |||||
private: | |||||
int i_; double d_; | |||||
}; | |||||
// A binary metafunction | |||||
template <typename T1, typename T2> | |||||
struct mFun { | |||||
using type = std::is_same <T1, T2>; | |||||
}; | |||||
// detectors | |||||
template <typename T> using try_type = typename T::type; | |||||
template <typename T> using try_none = typename T::none; | |||||
template <typename T> using try_ctor1= decltype (T(std::declval<int>(), std::declval<double>())); | |||||
template <typename T> using try_ctor2= decltype (T(std::declval<int>())); | |||||
template <typename T> using try_ppT = decltype (++(std::declval<T>())); | |||||
template <typename T> using try_Tpp = decltype (std::declval<T>()++); | |||||
template <typename T> using try_sfun = decltype (std::declval<T>().sfun()); | |||||
/* | |||||
* void_t | |||||
*/ | |||||
TEST(TmetaDetection, VoidType) { | |||||
EXPECT_EQ(true, (std::is_same<void, void_t<int, long, void*, void, Foo, Bar>>())); | |||||
EXPECT_EQ(true, (std::is_same<void, void_t<>>())); | |||||
} | |||||
/* | |||||
* not a type | |||||
*/ | |||||
TEST(TmetaDetection, NotAType) { | |||||
EXPECT_EQ(false, (std::is_default_constructible<nat_>())); | |||||
EXPECT_EQ(false, (std::is_destructible<nat_>())); | |||||
EXPECT_EQ(false, (std::is_copy_constructible<nat_>())); | |||||
EXPECT_EQ(false, (std::is_copy_assignable<nat_>())); | |||||
} | |||||
/* | |||||
* Idiom | |||||
*/ | |||||
TEST(TmetaDetection, IsDetected) { | |||||
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_type, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_none, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_ctor1, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_ctor2, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_ppT, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_Tpp, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< true_, is_detected<try_sfun, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< false_, is_detected<try_sfun, A<double>> >())); | |||||
EXPECT_EQ (true, (std::is_same< true_, is_detected<mFun, int, void> >())); | |||||
EXPECT_EQ (true, (std::is_same< false_, is_detected<mFun, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< false_, is_detected<mFun, char, void, void> >())); | |||||
EXPECT_EQ (true, (is_detected_v<try_type, A<int>>)); | |||||
EXPECT_EQ (false,(is_detected_v<try_none, A<int>>)); | |||||
EXPECT_EQ (true, (is_detected_v<mFun, int, void>)); | |||||
// typePrinter (detected_t<try_none, A>{}); | |||||
} | |||||
/* | |||||
* Idiom | |||||
*/ | |||||
TEST(TmetaDetection, Toolkit) { | |||||
// detected_t | |||||
EXPECT_EQ (true, (std::is_same< int, detected_t<try_type, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_none, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< A<int>, detected_t< try_ctor1, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_ctor2, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< A<int>&,detected_t< try_ppT, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_Tpp, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< int, detected_t< try_sfun, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nat_, detected_t< try_sfun, A<double>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nat_, detected_t<mFun, void> >())); | |||||
EXPECT_EQ (true, (std::is_same< mFun<int, int>, | |||||
detected_t<mFun, int, int> >())); | |||||
// detected_or_t | |||||
EXPECT_EQ (true, (std::is_same< int, detected_or_t<Foo, try_type, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< Foo, detected_or_t<Foo, try_none, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< A<int>, detected_or_t<void, try_ctor1, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< void, detected_or_t<void, try_ctor2, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< A<int>&,detected_or_t<nil_, try_ppT, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nil_, detected_or_t<nil_, try_Tpp, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< int, detected_or_t<void*, try_sfun, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same< void*, detected_or_t<void*, try_sfun, A<double>> >())); | |||||
EXPECT_EQ (true, (std::is_same< nil_, detected_or_t<nil_, mFun, int> >())); | |||||
EXPECT_EQ (true, (std::is_same< mFun<char, int>, | |||||
detected_or_t<void, mFun, char, int> >())); | |||||
// is_detected_exact | |||||
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< int, try_type, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< int, try_none, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< A<int>, try_ctor1, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< A<int>, try_ctor2, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< A<int>&,try_ppT, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< A<int>&,try_Tpp, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact< int, try_sfun, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact< int, try_sfun, A<double>> >())); | |||||
EXPECT_EQ (true, (std::is_same<true_, is_detected_exact<mFun<char, int>, mFun, char, int> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_exact<mFun<int, int>, mFun, int> >())); // it would be better to check against mFun<int> | |||||
EXPECT_EQ (true, (is_detected_exact_v< int, try_type, A<int>> )); | |||||
EXPECT_EQ (false,(is_detected_exact_v< int, try_none, A<int>> )); | |||||
// is_detected_convertible | |||||
EXPECT_EQ (true, (std::is_same<true_, is_detected_convertible< int, try_type, A<char>> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_convertible< int, try_none, A<int>> >())); | |||||
EXPECT_EQ (true, (std::is_same<false_, is_detected_convertible< mFun<int, int>, mFun, char, int> >())); | |||||
EXPECT_EQ (true, (is_detected_convertible_v< int, try_type, A<char>> )); | |||||
EXPECT_EQ (false,(is_detected_convertible_v< int, try_none, A<int>> )); | |||||
} | |||||
} |
@@ -1,5 +1,5 @@ | |||||
/*! | /*! | ||||
* \file Tmeta.cpp | |||||
* \file TmetaTypelist.cpp | |||||
* | * | ||||
* Copyright (C) 2018 Christos Choutouridis | * Copyright (C) 2018 Christos Choutouridis | ||||
* | * | ||||
@@ -21,7 +21,7 @@ | |||||
#include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||
#include <type_traits> | #include <type_traits> | ||||
namespace test_meta { | |||||
namespace TmetaTypelist { | |||||
using namespace utl; | using namespace utl; | ||||
using namespace meta; | using namespace meta; | ||||
@@ -53,168 +53,91 @@ namespace test_meta { | |||||
using type = std::is_void<T>; | using type = std::is_void<T>; | ||||
}; | }; | ||||
/* | |||||
* Test integral constant | |||||
*/ | |||||
TEST(Tmeta, IntegrealType) { | |||||
EXPECT_EQ(true, (std::is_same<int, eval<Identity<int>>>::value)); | |||||
} | |||||
TEST(Tmeta, IntegrealConstant) { | |||||
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::value_type>::value)); | |||||
EXPECT_EQ(true, (std::is_same<int, integral_<int, 42>::type::value_type>::value)); | |||||
EXPECT_EQ(42, (integral_<int, 0>::value_type(42))); | |||||
EXPECT_EQ(42, (integral_<int, 42>())); | |||||
} | |||||
TEST(Tmeta, BasicTypes) { | |||||
EXPECT_EQ(true, (std::is_same<bool, bool_<false>::value_type>::value)); | |||||
EXPECT_EQ(true, bool_<true>::value); | |||||
EXPECT_EQ(true, (std::is_same<bool, false_::value_type>::value)); | |||||
EXPECT_EQ(false, false_::value); | |||||
EXPECT_EQ(true, (std::is_same<bool, true_::value_type>::value)); | |||||
EXPECT_EQ(true, true_::value); | |||||
EXPECT_EQ(true, (std::is_same<int8_t, int8_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int8_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<uint8_t, uint8_<0>::value_type>::value)); | |||||
EXPECT_EQ(42u, uint8_<42u>::value); | |||||
EXPECT_EQ(true, (std::is_same<int16_t, int16_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int16_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<uint16_t, uint16_<0>::value_type>::value)); | |||||
EXPECT_EQ(42u, uint16_<42u>::value); | |||||
EXPECT_EQ(true, (std::is_same<int32_t, int32_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int32_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<uint32_t, uint32_<0>::value_type>::value)); | |||||
EXPECT_EQ(42u, uint32_<42u>::value); | |||||
EXPECT_EQ(true, (std::is_same<char, char_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, char_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<int, int_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, int_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<long, long_<0>::value_type>::value)); | |||||
EXPECT_EQ(42, long_<42>::value); | |||||
EXPECT_EQ(true, (std::is_same<index_t, index_<0>::value_type>::value)); | |||||
EXPECT_EQ(42U, index_<42U>::value); | |||||
EXPECT_EQ(true, (std::is_same<size_t, size_<0>::value_type>::value)); | |||||
EXPECT_EQ(42U, size_<42U>::value); | |||||
EXPECT_EQ(sizeof(int), sizeof_<int>::value); | |||||
EXPECT_EQ(alignof(int), alignof_<int>::value); | |||||
EXPECT_EQ(static_cast<index_t>(-1), Npos::value); | |||||
} | |||||
/* | |||||
* Test integral constant arithmetic operations | |||||
*/ | |||||
TEST(Tmeta, ArithmeticOperations) { | |||||
EXPECT_EQ (int_<42>(), inc<int_<41>>()); | |||||
EXPECT_EQ (int_<42>(), dec<int_<43>>()); | |||||
EXPECT_EQ (int_<42>(), (add<int_<23>, add<int_<17>, int_<2>>>())); | |||||
EXPECT_EQ (int_<42>(), (sub<int_<108>, int_<66>>())); | |||||
EXPECT_EQ (int_<42>(), (mult<int_<7>, mult<int_<3>, int_<2>>>())); | |||||
EXPECT_EQ (int_<42>(), (divide<int_<210>, int_<5>>())); | |||||
EXPECT_EQ (int_<42>(), negate<int_<-42>>()); | |||||
EXPECT_EQ (int_< 1>(), (modulo<int_<43>, int_<42>>())); | |||||
} | |||||
/* | |||||
* Test logical | |||||
*/ | |||||
TEST(Tmeta, ComparisonOperations) { | |||||
EXPECT_EQ (true, (std::is_same<bool_<true>, not_c<false>>::value)); | |||||
EXPECT_EQ (true, (comp_eq<int_<7>, int_<7>>())); | |||||
EXPECT_EQ (true, (comp_ne<int_<42>, int_<7>>())); | |||||
EXPECT_EQ (true, (comp_lt<int_<42>, int_<43>>())); | |||||
EXPECT_EQ (true, (comp_gt<int_<43>, int_<42>>())); | |||||
EXPECT_EQ (true, (comp_le<int_<42>, int_<42>>())); | |||||
EXPECT_EQ (true, (comp_ge<int_<42>, int_<42>>())); | |||||
} | |||||
TEST(Tmeta, BitOperations) { | |||||
EXPECT_EQ (0x00, (bitand_<uint8_<0x55>, uint8_<0xAA>>())); | |||||
EXPECT_EQ (0xFF, (bitor_ <uint8_<0x55>, uint8_<0xAA>>())); | |||||
EXPECT_EQ (0xFA, (bitxor_<uint8_<0x55>, uint8_<0xAF>>())); | |||||
EXPECT_EQ (0x00, (bitnot_<uint8_<-1>>())); | |||||
EXPECT_EQ (0x04, (shift_left<uint8_<0x01>, uint8_<2>>())); | |||||
EXPECT_EQ (0x00, (shift_left<uint8_<0x80>, uint8_<1>>())); | |||||
EXPECT_EQ (0x02, (shift_right<uint8_<0x08>, uint8_<2>>())); | |||||
EXPECT_EQ (0x00, (shift_right<uint8_<0x01>, uint8_<1>>())); | |||||
} | |||||
TEST(Tmeta, TypeOperations) { | |||||
struct Foo {}; | |||||
struct Bar {}; | |||||
EXPECT_EQ (true, (std::is_same<bool_<true>, not_<bool_<false>>>())); | |||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_c<true, int_<42>, bool_<false>>>())); | |||||
EXPECT_EQ (true, (std::is_same<int_<42>, if_<bool_<true>, int_<42>, bool_<false>>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, or_<true_, false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, or_<false_, false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<false_, and_<true_, false_>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_>>())); | |||||
EXPECT_EQ (true, (same_<Foo, Foo>())); | |||||
EXPECT_EQ (false, (same_<Foo, Bar>())); | |||||
EXPECT_EQ (true, (not_same_<Foo, Bar>())); | |||||
} | |||||
/* | /* | ||||
* Test void_t | |||||
* Test high order metaFun tools | |||||
*/ | */ | ||||
TEST(Tmeta, VoidType) { | |||||
struct Foo {}; | |||||
struct Bar {}; | |||||
EXPECT_EQ(true, (std::is_same<void, void_t<int, long, Foo, Bar>>())); | |||||
} | |||||
/* | |||||
* Test invoke | |||||
*/ | |||||
TEST(Tmeta, Invoke) { | |||||
TEST(TmetaTypelist, Invoke) { | |||||
using W = wrap <MfunBin>; | |||||
using Wi = wrap_i<int, MfunBin_i>; | |||||
using W1 = wrap<MfunUn1>; | |||||
using W2 = wrap<MfunUn2>; | |||||
using Q = quote<MfunBin>; | using Q = quote<MfunBin>; | ||||
using Qi = quote_i<int, MfunBin_i>; | using Qi = quote_i<int, MfunBin_i>; | ||||
using Q1 = quote<MfunUn1>; | using Q1 = quote<MfunUn1>; | ||||
using Q2 = quote<MfunUn2>; | using Q2 = quote<MfunUn2>; | ||||
// identity | |||||
EXPECT_EQ (true, (std::is_same<int, eval<identity<int>>>())); | |||||
EXPECT_EQ (true, (std::is_same<int, identity_t<int>>())); | EXPECT_EQ (true, (std::is_same<int, identity_t<int>>())); | ||||
EXPECT_EQ (true, (std::is_same<void*, identity_t<void*>>())); | |||||
// invoke, check that invoke un-wraps and un-quotes staff | |||||
EXPECT_EQ (true, (std::is_same< invoke<wrap<MfunBin>, int, char>, MfunBin<int, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< invoke<quote<MfunBin>, int, char>, MfunBin<int, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< invoke<wrap_i<int, MfunBin_i>, int_<7>, int_<42>>, MfunBin_i<7, 42> >())); | |||||
EXPECT_EQ (true, (std::is_same< invoke<quote_i<int, MfunBin_i>, int_<7>, int_<42>>, MfunBin_i<7, 42> >())); | |||||
// Wrap | |||||
EXPECT_EQ (true, (std::is_same< wrap<MfunBin>::template apply<int, char>, MfunBin<int, char> >())); | |||||
EXPECT_EQ (false, (std::is_same< wrap<MfunBin>::template apply<int, char>, MfunBin<int, int> >())); | |||||
EXPECT_EQ (true, (std::is_same< wrap_i<int, MfunBin_i>::template apply<int_<7>, int_<42>>, MfunBin_i<7, 42> >())); | |||||
EXPECT_EQ (false, (std::is_same< wrap_i<int, MfunBin_i>::template apply<int_<7>, int_<42>>, MfunBin_i<42, 7> >())); | |||||
// applicable trait | |||||
EXPECT_EQ (true, (is_applicable_t<MfunBin, int, long>())); | EXPECT_EQ (true, (is_applicable_t<MfunBin, int, long>())); | ||||
EXPECT_EQ (false, (is_applicable_t<MfunBin, int>())); | EXPECT_EQ (false, (is_applicable_t<MfunBin, int>())); | ||||
EXPECT_EQ (true, (is_applicable_qt<Q, int, long>())); | EXPECT_EQ (true, (is_applicable_qt<Q, int, long>())); | ||||
EXPECT_EQ (false, (is_applicable_qt<Q, int>())); | EXPECT_EQ (false, (is_applicable_qt<Q, int>())); | ||||
EXPECT_EQ (true, (is_applicable_qt<W, int, long>())); | |||||
EXPECT_EQ (false, (is_applicable_qt<W, int>())); | |||||
EXPECT_EQ (true, (is_applicable_it<int, MfunBin_i, 7, 42>())); | EXPECT_EQ (true, (is_applicable_it<int, MfunBin_i, 7, 42>())); | ||||
EXPECT_EQ (false, (is_applicable_it<int, MfunBin_i, 42>())); | EXPECT_EQ (false, (is_applicable_it<int, MfunBin_i, 42>())); | ||||
// defer | |||||
EXPECT_EQ (true, (std::is_same<defer<MfunBin, int, void>::type, MfunBin<int, void>>())); | EXPECT_EQ (true, (std::is_same<defer<MfunBin, int, void>::type, MfunBin<int, void>>())); | ||||
EXPECT_EQ (true, (std::is_same<defer<MfunBin, void>::type, nil_>())); | EXPECT_EQ (true, (std::is_same<defer<MfunBin, void>::type, nil_>())); | ||||
EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7, 42>::type, MfunBin_i<7, 42>>())); | EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7, 42>::type, MfunBin_i<7, 42>>())); | ||||
EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7>::type, nil_>())); | EXPECT_EQ (true, (std::is_same<defer_i<int, MfunBin_i, 7>::type, nil_>())); | ||||
EXPECT_EQ (true, (std::is_same<invoke<Q, int>, nil_>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<Q, int, void*>, MfunBin<int, void*>>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<Qi, int_<7>, int_<42>>, MfunBin_i<7, 42>>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<Qi, int_<42>>, nil_>())); | |||||
// quote | |||||
EXPECT_EQ (true, (std::is_same< quote<MfunBin>::template apply<int, void*>, MfunBin<int, void*> >())); | |||||
EXPECT_EQ (false,(std::is_same< quote<MfunBin>::template apply<int, void*>, MfunBin<int, int> >())); | |||||
EXPECT_EQ (true, (std::is_same< quote_i<int, MfunBin_i>::template apply< int_<7>, int_<42>>, MfunBin_i<7, 42> >())); | |||||
EXPECT_EQ (false,(std::is_same< quote_i<int, MfunBin_i>::template apply< int_<7>, int_<42>>, MfunBin_i<42, 7> >())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose<Q1, Q2>, int>, MfunUn1<MfunUn2<int>>>())); | |||||
// compose | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose_f<MfunUn1>, int>, MfunUn1<int>>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose_f<MfunUn1, MfunUn2>, int>, MfunUn1<MfunUn2<int>>>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose<W1>, int>, MfunUn1<int>>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose<W1, W2>, int>, MfunUn1<MfunUn2<int>>>())); | |||||
EXPECT_EQ (true, (std::is_same< | EXPECT_EQ (true, (std::is_same< | ||||
invoke<compose<Q1, Q2, Qi>, int_<7>, int_<42>>, | |||||
MfunUn1<MfunUn2<MfunBin_i<7, 42>>> | |||||
>())); | |||||
invoke<compose<W1, W2, Wi>, int_<7>, int_<42>>, MfunUn1<MfunUn2<MfunBin_i<7, 42>>> | |||||
>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose<Q1>, int>, MfunUn1<int>>())); | |||||
EXPECT_EQ (true, (std::is_same<invoke<compose<Q1, Q2>, int>, MfunUn1<MfunUn2<int>>>())); | |||||
EXPECT_EQ (true, (std::is_same< | EXPECT_EQ (true, (std::is_same< | ||||
invoke<compose<Q1, Q2, Qi>, int_<42>>, | |||||
MfunUn1<MfunUn2<nil_>> | |||||
>())); | |||||
invoke<compose<Q1, Q2, Qi>, int_<7>, int_<42>>, MfunUn1<MfunUn2<MfunBin_i<7, 42>>> | |||||
>())); | |||||
// bind | |||||
EXPECT_EQ (true, (std::is_same<invoke<bind_front<Q, int>, long>, MfunBin<int, long>>())); | EXPECT_EQ (true, (std::is_same<invoke<bind_front<Q, int>, long>, MfunBin<int, long>>())); | ||||
EXPECT_EQ (true, (std::is_same<invoke<bind_back<Q, int>, long>, MfunBin<long, int>>())); | EXPECT_EQ (true, (std::is_same<invoke<bind_back<Q, int>, long>, MfunBin<long, int>>())); | ||||
// Check the case of ill formed parameter composition. Quote must save us | |||||
EXPECT_EQ (true, (std::is_same< nil_, invoke<Q, int> >())); | |||||
EXPECT_EQ (true, (std::is_same< nil_, invoke<Qi, int_<42>> >())); | |||||
EXPECT_EQ (true, (std::is_same< MfunUn1<MfunUn2<nil_>>, invoke<compose<Q1, Q2, Qi>, int_<42>> >())); | |||||
} | } | ||||
/* | /* | ||||
* Test typelist | * Test typelist | ||||
*/ | */ | ||||
TEST(Tmeta_typelist, Basics) { | |||||
TEST(TmetaTypelist, Basics) { | |||||
using l1 = typelist<int, int, int>; | using l1 = typelist<int, int, int>; | ||||
using l2 = typelist<int, void*, int, void*>; | using l2 = typelist<int, void*, int, void*>; | ||||
using l3 = typelist<>; | using l3 = typelist<>; | ||||
@@ -223,6 +146,7 @@ namespace test_meta { | |||||
EXPECT_EQ (true, (std::is_same<l2, typelist<int, void*>::times<2>>())); | EXPECT_EQ (true, (std::is_same<l2, typelist<int, void*>::times<2>>())); | ||||
EXPECT_EQ (true, (std::is_same<l3, typelist<>::times<3>>())); | EXPECT_EQ (true, (std::is_same<l3, typelist<>::times<3>>())); | ||||
EXPECT_EQ (true, (std::is_same<l3, typelist<int>::times<0>>())); | EXPECT_EQ (true, (std::is_same<l3, typelist<int>::times<0>>())); | ||||
EXPECT_EQ (true, (std::is_same<l3, typelist<int, void>::times<0>>())); | |||||
EXPECT_EQ (true, (std::is_same<typelist<short, double>, pair<short, double>>())); | EXPECT_EQ (true, (std::is_same<typelist<short, double>, pair<short, double>>())); | ||||
EXPECT_EQ (true, (std::is_same<l1, repeat <int_<3>, int>>())); | EXPECT_EQ (true, (std::is_same<l1, repeat <int_<3>, int>>())); | ||||
@@ -230,29 +154,30 @@ namespace test_meta { | |||||
EXPECT_EQ (3, size<l1>()); | EXPECT_EQ (3, size<l1>()); | ||||
EXPECT_EQ (0, size<l3>()); | |||||
EXPECT_EQ (true, empty<l3>()); | EXPECT_EQ (true, empty<l3>()); | ||||
// pass typelist to an invocable | // pass typelist to an invocable | ||||
EXPECT_EQ (true, (std::is_same<eval< | |||||
apply<quote<MfunBin>, typelist<int, long>> | |||||
>, | |||||
MfunBin<int, long> | |||||
>())); | |||||
EXPECT_EQ (true, (std::is_same< apply_t<quote<MfunUn1>, typelist<int>>, MfunUn1<int> >())); | |||||
EXPECT_EQ (true, (std::is_same< apply_t<quote<MfunBin>, typelist<int, long>>, MfunBin<int, long> >())); | |||||
} | } | ||||
TEST(Tmeta_typelist, Element_access) { | |||||
using l = typelist<char, void, long, double, short>; | |||||
TEST(TmetaTypelist, ElementAccess) { | |||||
using l = typelist<char*, void, void*, long, double, short>; | |||||
EXPECT_EQ (true, (std::is_same<char*, at_c<l, 0>>())); | |||||
EXPECT_EQ (true, (std::is_same<void*, at_c<l, 2>>())); | |||||
EXPECT_EQ (true, (std::is_same<short, at_c<l, 5>>())); | |||||
EXPECT_EQ (true, (std::is_same<nil_, at_c<l, 6>>())); | |||||
EXPECT_EQ (true, (std::is_same<char, at_c<l, 0>>())); | |||||
EXPECT_EQ (true, (std::is_same<long, at_c<l, 2>>())); | |||||
EXPECT_EQ (true, (std::is_same<nil_, at_c<l, 5>>())); | |||||
EXPECT_EQ (true, (std::is_same<void, at<l, int_<1>>>())); | EXPECT_EQ (true, (std::is_same<void, at<l, int_<1>>>())); | ||||
EXPECT_EQ (true, (std::is_same<long, at<l, int_<3>>>())); | |||||
EXPECT_EQ (true, (std::is_same<char, front<l>>())); | |||||
EXPECT_EQ (true, (std::is_same<char*, front<l>>())); | |||||
EXPECT_EQ (true, (std::is_same<short, back<l>>())); | EXPECT_EQ (true, (std::is_same<short, back<l>>())); | ||||
} | } | ||||
TEST(Tmeta_typelist, Concat) { | |||||
TEST(TmetaTypelist, Concat) { | |||||
using l1 = typelist<int, long, void>; | using l1 = typelist<int, long, void>; | ||||
using l2 = typelist<void*, int*>; | using l2 = typelist<void*, int*>; | ||||
using l3 = typelist<double, long double, short>; | using l3 = typelist<double, long double, short>; | ||||
@@ -266,7 +191,7 @@ namespace test_meta { | |||||
} | } | ||||
template<class T1, class T2> struct F {}; // binary invocable | template<class T1, class T2> struct F {}; // binary invocable | ||||
TEST(Tmeta_typelist, Fold) { | |||||
TEST(TmetaTypelist, Fold) { | |||||
struct X1 {}; | struct X1 {}; | ||||
struct X2 {}; | struct X2 {}; | ||||
struct X3 {}; | struct X3 {}; | ||||
@@ -286,7 +211,7 @@ namespace test_meta { | |||||
EXPECT_EQ(true, (std::is_same<rev_fold<typelist<X1, X2, X3, X4>, void, Q>, F<X1, F<X2, F<X3, F<X4, void>>>>>())); | EXPECT_EQ(true, (std::is_same<rev_fold<typelist<X1, X2, X3, X4>, void, Q>, F<X1, F<X2, F<X3, F<X4, void>>>>>())); | ||||
} | } | ||||
TEST(Tmeta_typelist, PushPopReverse) { | |||||
TEST(TmetaTypelist, PushPopReverse) { | |||||
using list = typelist <int, long, void>; | using list = typelist <int, long, void>; | ||||
using l_char = typelist <int, long, void, char>; | using l_char = typelist <int, long, void, char>; | ||||
using l_cc = typelist <int, long, void, char, char>; | using l_cc = typelist <int, long, void, char, char>; | ||||
@@ -294,19 +219,19 @@ namespace test_meta { | |||||
using cc_l = typelist<char, char, int, long, void>; | using cc_l = typelist<char, char, int, long, void>; | ||||
using rev = typelist<void, long, int>; | using rev = typelist<void, long, int>; | ||||
EXPECT_EQ (true, (std::is_same<char_l, push_front<list, char>>())); | |||||
EXPECT_EQ (true, (std::is_same<cc_l, push_front<list, char, char>>())); | |||||
EXPECT_EQ (true, (std::is_same<list, pop_front <char_l>>())); | |||||
EXPECT_EQ (true, (std::is_same<l_char, push_back <list, char>>())); | |||||
EXPECT_EQ (true, (std::is_same<l_cc, push_back <list, char, char>>())); | |||||
EXPECT_EQ (true, (std::is_same<list, pop_back <l_char>>())); | |||||
EXPECT_EQ (true, (std::is_same< char_l, push_front<list, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< cc_l, push_front<list, char, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< list, pop_front <char_l> >())); | |||||
EXPECT_EQ (true, (std::is_same< l_char, push_back <list, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< l_cc, push_back <list, char, char> >())); | |||||
EXPECT_EQ (true, (std::is_same< list, pop_back <l_char> >())); | |||||
EXPECT_EQ (true, (std::is_same<rev, reverse <list>>())); | |||||
EXPECT_EQ (true, (std::is_same< rev, reverse <list> >())); | |||||
} | } | ||||
TEST(Tmeta_typelist, Transform) { | |||||
using QBin = quote<MfunBin>; | |||||
using QUn = quote<MfunUn1>; | |||||
TEST(TmetaTypelist, Transform) { | |||||
using QBin = quote<MfunBin>; // both metafuctions return int | |||||
using QUn = quote<MfunUn1>; | |||||
using l1 = typelist<char, int, float>; | using l1 = typelist<char, int, float>; | ||||
using l2 = typelist<void, void, void>; | using l2 = typelist<void, void, void>; | ||||
@@ -322,7 +247,7 @@ namespace test_meta { | |||||
} | } | ||||
TEST(Tmeta_typelist, Find) { | |||||
TEST(TmetaTypelist, Find) { | |||||
using l1 = typelist <int, char, long, float>; | using l1 = typelist <int, char, long, float>; | ||||
using l2 = typelist <char, long, float>; | using l2 = typelist <char, long, float>; | ||||
using l3 = typelist <long, float>; | using l3 = typelist <long, float>; | ||||
@@ -341,7 +266,7 @@ namespace test_meta { | |||||
EXPECT_EQ(true, (std::is_same<l3, seek<l1, long>>())); | EXPECT_EQ(true, (std::is_same<l3, seek<l1, long>>())); | ||||
} | } | ||||
TEST(Tmeta_typelist, Count) { | |||||
TEST(TmetaTypelist, Count) { | |||||
using list = typelist<int, void*, char, int, long*, char, int, short>; | using list = typelist<int, void*, char, int, long*, char, int, short>; | ||||
using empty = typelist<>; | using empty = typelist<>; | ||||
@@ -353,7 +278,7 @@ namespace test_meta { | |||||
EXPECT_EQ (true, (std::is_same<size_<1>, count<list, void*>>())); | EXPECT_EQ (true, (std::is_same<size_<1>, count<list, void*>>())); | ||||
} | } | ||||
TEST(Tmeta_typelist, Filter) { | |||||
TEST(TmetaTypelist, Filter) { | |||||
using Q1 = quote<Pred_isInt>; | using Q1 = quote<Pred_isInt>; | ||||
using Q2 = quote<Pred_isVoid>; | using Q2 = quote<Pred_isVoid>; | ||||
using list = typelist<int, float, char, long*, short, double, void*>; | using list = typelist<int, float, char, long*, short, double, void*>; | ||||
@@ -362,9 +287,10 @@ namespace test_meta { | |||||
EXPECT_EQ (true, (std::is_same<filtered, filter<list, Q1>>())); | EXPECT_EQ (true, (std::is_same<filtered, filter<list, Q1>>())); | ||||
EXPECT_EQ (true, (std::is_same<typelist<>, filter<typelist<>, Q1>>())); | EXPECT_EQ (true, (std::is_same<typelist<>, filter<typelist<>, Q1>>())); | ||||
EXPECT_EQ (true, (std::is_same<typelist<>, filter<list, Q2>>())); | EXPECT_EQ (true, (std::is_same<typelist<>, filter<list, Q2>>())); | ||||
EXPECT_EQ (true, (std::is_same<typelist<>, filter<typelist<>, Q1>>())); | |||||
} | } | ||||
TEST(Tmeta_typelist, Replace) { | |||||
TEST(TmetaTypelist, Replace) { | |||||
using Q = quote<Pred_isInt>; | using Q = quote<Pred_isInt>; | ||||
using list = typelist<int, float, char, long*, short, double, void*>; | using list = typelist<int, float, char, long*, short, double, void*>; | ||||
using res = typelist<void,float, void, long*, void, double, void*>; | using res = typelist<void,float, void, long*, void, double, void*>; | ||||
@@ -373,22 +299,44 @@ namespace test_meta { | |||||
EXPECT_EQ (true, (std::is_same<res, replace_if<list, Q, void>>())); | EXPECT_EQ (true, (std::is_same<res, replace_if<list, Q, void>>())); | ||||
EXPECT_EQ (true, (std::is_same<typelist<>, replace_if<typelist<>, Q, void>>())); | EXPECT_EQ (true, (std::is_same<typelist<>, replace_if<typelist<>, Q, void>>())); | ||||
EXPECT_EQ (true, (std::is_same<res, replace_if<res, Q, void>>())); | EXPECT_EQ (true, (std::is_same<res, replace_if<res, Q, void>>())); | ||||
EXPECT_EQ (true, (std::is_same<typelist<>, replace_if<typelist<>, Q, void>>())); | |||||
EXPECT_EQ (true, (std::is_same<repl, replace<list, char, void>>())); | EXPECT_EQ (true, (std::is_same<repl, replace<list, char, void>>())); | ||||
EXPECT_EQ (true, (std::is_same<typelist<>, replace<typelist<>, char, void>>())); | |||||
} | } | ||||
TEST (Tmeta_typelist, AllAnyNone) { | |||||
TEST (TmetaTypelist, AllAnyNone) { | |||||
using l1 = typelist<int, float, char, long*, short, double, void*>; | using l1 = typelist<int, float, char, long*, short, double, void*>; | ||||
using l2 = typelist<int, char, long, short>; | using l2 = typelist<int, char, long, short>; | ||||
using l3 = typelist<>; | |||||
EXPECT_EQ (true, (std::is_same<false_, all_of<l1, quote<Pred_isInt>>>())); | EXPECT_EQ (true, (std::is_same<false_, all_of<l1, quote<Pred_isInt>>>())); | ||||
EXPECT_EQ (true, (std::is_same<true_, all_of<l2, quote<Pred_isInt>>>())); | EXPECT_EQ (true, (std::is_same<true_, all_of<l2, quote<Pred_isInt>>>())); | ||||
EXPECT_EQ (true, (std::is_same<false_, all_of<l3, quote<Pred_isVoid>>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, any_of<l1, quote<Pred_isInt>>>())); | EXPECT_EQ (true, (std::is_same<true_, any_of<l1, quote<Pred_isInt>>>())); | ||||
EXPECT_EQ (true, (std::is_same<false_, any_of<l2, quote<Pred_isVoid>>>())); | EXPECT_EQ (true, (std::is_same<false_, any_of<l2, quote<Pred_isVoid>>>())); | ||||
EXPECT_EQ (true, (std::is_same<false_, any_of<l3, quote<Pred_isVoid>>>())); | |||||
EXPECT_EQ (true, (std::is_same<true_, none_of<l1, quote<Pred_isVoid>>>())); | EXPECT_EQ (true, (std::is_same<true_, none_of<l1, quote<Pred_isVoid>>>())); | ||||
EXPECT_EQ (true, (std::is_same<false_, none_of<l1, quote<Pred_isInt>>>())); | EXPECT_EQ (true, (std::is_same<false_, none_of<l1, quote<Pred_isInt>>>())); | ||||
EXPECT_EQ (true, (std::is_same<true_, none_of<l3, quote<Pred_isInt>>>())); | |||||
} | } | ||||
/* | |||||
* Detection idiom | |||||
*/ | |||||
TEST(Tmeta, DetectionVoidType) { | |||||
struct Foo {}; | |||||
struct Bar {}; | |||||
EXPECT_EQ(true, (std::is_same<void, void_t<int, long, void*, void, Foo, Bar>>())); | |||||
EXPECT_EQ(true, (std::is_same<void, void_t<>>())); | |||||
} | |||||
TEST(Tmeta, DetectionNotAType) { | |||||
EXPECT_EQ(false, (std::is_default_constructible<nat_>())); | |||||
EXPECT_EQ(false, (std::is_destructible<nat_>())); | |||||
EXPECT_EQ(false, (std::is_copy_constructible<nat_>())); | |||||
EXPECT_EQ(false, (std::is_copy_assignable<nat_>())); | |||||
} | |||||
} | } |
@@ -68,7 +68,7 @@ namespace test_i2c { | |||||
uint8_t b = 42; | uint8_t b = 42; | ||||
i2c.clock(200000UL); | i2c.clock(200000UL); | ||||
EXPECT_EQ(i2c.clock(), 200000UL); | |||||
//EXPECT_EQ(i2c.clock(), 200000UL); | |||||
EXPECT_EQ(i2c.tx_data(b), true); | EXPECT_EQ(i2c.tx_data(b), true); | ||||
EXPECT_EQ(i2c.rx_data(true), 0x00); | EXPECT_EQ(i2c.rx_data(true), 0x00); | ||||