@@ -0,0 +1,113 @@ | |||
/*! | |||
* \file pack.h | |||
* \brief Template meta-programming parameter pack container | |||
* | |||
* 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/>. | |||
*/ | |||
#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_<type_<make_index_tuple_<_Num / 2>>, | |||
type_<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 = type_<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 = type_<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__ */ |
@@ -1,5 +1,5 @@ | |||
/*! | |||
* \file integral.h | |||
* \file integralconstant.h | |||
* \brief Template meta-programming integral constant | |||
* | |||
* Copyright (C) 2018 Christos Choutouridis | |||
@@ -17,38 +17,102 @@ | |||
* 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_integral_h__ | |||
#define __utl_meta_integral_h__ | |||
#ifndef __utl_meta_integralconstant_h__ | |||
#define __utl_meta_integralconstant_h__ | |||
#include <utl/core/impl.h> | |||
#include <utl/impl/impl.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup integral | |||
* integral constand support header | |||
* integral constant support header | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta { | |||
//! Empty type | |||
struct nil_ { }; | |||
//! Type alias for \p _Tp::type. Used to extract return type of metafunctions | |||
template <typename _Tp> | |||
using type_ = typename _Tp::type; | |||
//! integral_constant | |||
//! An Integral Constant is a holder class for a compile-time value of an integral type. | |||
//! Every Integral Constant is also a nullary Metafunction, returning itself. | |||
//! An integral constant object is implicitly convertible to the corresponding | |||
//! run-time value of the wrapped integral type | |||
//! @{ | |||
template <typename _Tp, _Tp _v> | |||
struct integral_ { | |||
struct integral_constant { | |||
using value_type = _Tp; | |||
using type = integral_<_Tp, _v>; | |||
using type = integral_constant<_Tp, _v>; | |||
constexpr operator value_type() const { | |||
constexpr operator value_type() const noexcept { | |||
return value; | |||
} | |||
constexpr value_type operator()() const { | |||
constexpr value_type operator()() const noexcept { | |||
return value; | |||
} | |||
static constexpr _Tp value = _v; | |||
}; | |||
template<typename _Tp, _Tp _v> | |||
constexpr _Tp integral_<_Tp, _v>::value; | |||
} | |||
constexpr _Tp integral_constant<_Tp, _v>::value; | |||
//! @} | |||
//! Wrappers for basic types | |||
//! @{ | |||
//! integral constant | |||
template <typename _Tp, _Tp _v> | |||
using integral_c = integral_constant<_Tp, _v>; | |||
//! bool_ type: integral constant wrapper for bool | |||
template<bool _v> | |||
using bool_ = integral_c<bool, _v>; | |||
using true_ = bool_<true>; //!< The type used as a compile-time boolean with true value. | |||
using false_ = bool_<false>; //!< The type used as a compile-time boolean with false value. | |||
//! char_ type: integral constant wrapper for \c char | |||
template<char _v> | |||
using char_ = integral_c<char, _v>; | |||
//! int_ type: integral constant wrapper for \c int | |||
template<int _v> | |||
using int_ = integral_c<int, _v>; | |||
//! long_ type: integral constant wrapper for \c long | |||
template<long _v> | |||
using long_ = integral_c<long, _v>; | |||
//! index_t_ type: integral constant wrapper for \c index_t a.k.a std::size_t | |||
template<index_t _v> | |||
using index_t_ = integral_c<index_t, _v>; | |||
//! size_t_ type: integral constant wrapper for \c size_t a.k.a std::size_t | |||
template<size_t _v> | |||
using size_t_ = integral_constant<size_t, _v>; | |||
//! Computes the size of the type \p _Tp. | |||
//! Complexity \f$ O(1) \f$. | |||
template <typename _Tp> | |||
using sizeof_ = size_t_<sizeof(_Tp)>; | |||
//! Computes the alignment required for any instance of the type \p _Tp. | |||
//! Complexity \f$ O(1) \f$. | |||
template <typename _Tp> | |||
using alignof_ = size_t_<alignof(_Tp)>; | |||
//! @} | |||
//! The last position we can express for indexing | |||
using Npos = size_t_<index_t(-1)>; | |||
}} | |||
//!@} | |||
#endif /* __utl_meta_integral_h__ */ | |||
#endif /* __utl_meta_integralconstant_h__ */ |
@@ -0,0 +1,63 @@ | |||
/*! | |||
* \file void.h | |||
* \brief Template meta-programming void helpers | |||
* | |||
* 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/>. | |||
*/ | |||
#ifndef __utl_meta_void_h__ | |||
#define __utl_meta_void_h__ | |||
#include <utl/impl/impl.h> | |||
#include <utl/meta/bool.h> | |||
/*! \ingroup meta | |||
* \defgroup void | |||
* void_ support header | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
/*! | |||
* Like boost::mpl we made void_ a complete type to allow it to be | |||
* instantiated so that it can be passed in as an object that can be | |||
* used to select an overloaded function. | |||
*/ | |||
struct void_ { | |||
typedef void_ type; | |||
}; | |||
template<typename _Tp> | |||
struct is_void_ | |||
: false_ { }; | |||
template<> | |||
struct is_void_ <void_> | |||
: true_ { }; | |||
template<typename _Tp> | |||
struct is_not_void_ | |||
: true_ { }; | |||
template<> | |||
struct is_not_void_<void_> | |||
: false_ { }; | |||
} | |||
//!@} | |||
#endif /* __utl_meta_void_h__ */ |
@@ -20,9 +20,8 @@ | |||
#ifndef __utl_meta_logical_h__ | |||
#define __utl_meta_logical_h__ | |||
#include <utl/impl/impl.h> | |||
#include <utl/meta/bool.h> | |||
#include <utl/meta/if.h> | |||
#include <utl/core/impl.h> | |||
#include <utl/meta/selection.h> | |||
/*! | |||
* \ingroup meta | |||
@@ -31,51 +30,69 @@ | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta{ | |||
//! NOT implementation | |||
template<bool C_> | |||
struct not_ : bool_<!C_> { }; | |||
/*! | |||
* 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 | |||
//! @{ | |||
template<typename...> struct or_; | |||
namespace detail { | |||
template<typename...> struct _or_; | |||
template<> | |||
struct or_<> | |||
: false_ { }; | |||
template<> | |||
struct _or_<> : false_ { }; | |||
template<typename _T1> | |||
struct or_<_T1> | |||
: _T1 { }; | |||
template<typename _T1> | |||
struct _or_<_T1> : _T1 { }; | |||
template<typename _T1, typename _T2> | |||
struct or_ <_T1, _T2> | |||
: select_<_T1::value, _T1, _T2> { }; | |||
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 _T1, typename _T2, typename _T3, typename... _Tn> | |||
struct or_<_T1, _T2, _T3, _Tn...> | |||
: select_<_T1::value, _T1, or_<_T2, _T3, _Tn...>> { }; | |||
template <typename... _Ts> | |||
using or_ = type_<detail::_or_<_Ts...>>; | |||
//! @} | |||
//! AND implementation | |||
//! @{ | |||
template<typename...> struct and_; | |||
namespace detail { | |||
template<typename...> struct _and_; | |||
template<> | |||
struct and_<> | |||
: true_ { }; | |||
template<> | |||
struct _and_<> | |||
: true_ { }; | |||
template<typename _T1> | |||
struct and_ <_T1> | |||
: _T1 { }; | |||
template<typename _T1> | |||
struct _and_ <_T1> | |||
: _T1 { }; | |||
template<typename _T1, typename _T2> | |||
struct and_<_T1, _T2> | |||
: select_<_T1::value, _T2, _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 _T1, typename _T2, typename _T3, typename... _Tn> | |||
struct and_<_T1, _T2, _T3, _Tn...> | |||
: select_<_T1::value, and_<_T2, _T3, _Tn...>, _T1> { }; | |||
template <typename... _Ts> | |||
using and_ = type_<detail::_and_<_Ts...>>; | |||
//! @} | |||
//! same | |||
@@ -90,11 +107,12 @@ namespace utl { | |||
//! not same | |||
//! @{ | |||
template<typename _T1, typename _T2> | |||
struct not_same_ : true_ { }; | |||
using not_same_ = not_<type_<same_<_T1, _T2>>>; | |||
//! @} | |||
template<typename _Tp> | |||
struct not_same_ <_Tp, _Tp> : false_ { }; | |||
//! @} | |||
} | |||
}} | |||
//! @} | |||
#endif /* __utl_meta_logical_h__ */ |
@@ -0,0 +1,33 @@ | |||
/*! | |||
* \file /utl/core/version.h | |||
* \brief version and cpp version checks | |||
* | |||
* 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/>. | |||
* | |||
*/ | |||
#ifndef __utl_meta_meta_h__ | |||
#define __utl_meta_meta_h__ | |||
#include <utl/meta/void.h> | |||
#include <utl/meta/integral.h> | |||
#include <utl/meta/typelist.h> | |||
#include <utl/meta/selection.h> | |||
#include <utl/meta/logical.h> | |||
#include <utl/meta/operations.h> | |||
#include <utl/meta/useif.h> | |||
#endif /* __utl_meta_meta_h__ */ |
@@ -0,0 +1,132 @@ | |||
/*! | |||
* \file operators.h | |||
* \brief Template meta-programming integral constant arithmetic | |||
* | |||
* 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/>. | |||
*/ | |||
#ifndef __utl_meta_arithmetic_h__ | |||
#define __utl_meta_arithmetic_h__ | |||
#include <utl/core/impl.h> | |||
#include <utl/meta/logical.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup integral operators | |||
* Type arithmetic and operators | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta { | |||
/*! | |||
* Math operations | |||
* requires IntegralConstant(_Tp) | |||
*/ | |||
//! @{ | |||
//! Negation | |||
template <typename _Tp> | |||
using negate = integral_constant<decltype(-_Tp()), -_Tp()>; | |||
//! Addition | |||
template <typename _Tp1, typename _Tp2> | |||
using add = integral_constant< | |||
decltype(_Tp1() + _Tp2()), | |||
_Tp1() + _Tp2() | |||
>; | |||
//! Multiplication | |||
template <typename _Tp1, typename _Tp2> | |||
using mult = integral_constant< | |||
decltype(_Tp2() * _Tp2()), | |||
_Tp1() * _Tp2() | |||
>; | |||
//! Division | |||
template <typename _Tp1, typename _Tp2> | |||
using divide = integral_constant< | |||
decltype(_Tp2() / _Tp2()), | |||
_Tp1() / _Tp2() | |||
>; | |||
//! Modulo | |||
template <typename _Tp1, typename _Tp2> | |||
using modulo = integral_constant< | |||
decltype(_Tp1() % _Tp2()), | |||
_Tp1() % _Tp2() | |||
>; | |||
//! Substruction | |||
template <typename _Tp1, typename _Tp2> | |||
using sub = add<_Tp1, negate<_Tp2>>; | |||
//! Increase | |||
template <typename _Tp> | |||
using inc = add<_Tp, int_<1>>; | |||
//! decrease | |||
template <typename _Tp> | |||
using dec = add<_Tp, int_<-1>>; | |||
//! @} | |||
/*! | |||
* Comparison operations | |||
* requires IntegralConstant(_Tp) | |||
*/ | |||
//! @{ | |||
//! \return a true-valued Integral Constant if _Tp1 and _Tp2 are equal. | |||
template <typename _Tp1, typename _Tp2> using comp_eq = bool_<_Tp1() == _Tp2()>; | |||
//! \return a true-valued Integral Constant if _Tp1 is less than _Tp2. | |||
template <typename _Tp1, typename _Tp2> using comp_lt = bool_<(_Tp1() < _Tp2())>; | |||
//! Not equal | |||
template <typename _Tp1, typename _Tp2> using comp_ne = not_<comp_eq<_Tp1, _Tp2>>; | |||
//! Greater than | |||
template <typename _Tp1, typename _Tp2> using comp_gt = comp_lt <_Tp2, _Tp1>; | |||
//! Less or equal | |||
template <typename _Tp1, typename _Tp2> using comp_le = not_<comp_lt<_Tp2, _Tp1>>; | |||
//! Greater or equal | |||
template <typename _Tp1, typename _Tp2> using comp_ge = not_<comp_lt<_Tp1, _Tp2>>; | |||
//! @} | |||
/*! | |||
* Bitwise operations | |||
* requires IntegralConstant(_Tp) | |||
*/ | |||
//! @{ | |||
//! \return bitwise not (~) operation of its argument. | |||
template <typename _T> using bitnot_ = integral_c<decltype(~_T()), ~_T()>; | |||
//! \return bitwise and (&) operation of its arguments | |||
template <typename _Tp1, typename _Tp2> | |||
using bitand_ = integral_c<decltype(_Tp1() & _Tp2()), _Tp1() & _Tp2()>; | |||
//! \return bitwise or (|) operation of its arguments. | |||
template <typename _Tp1, typename _Tp2> | |||
using bitor_ = integral_c<decltype(_Tp1() | _Tp2()), _Tp1() | _Tp2()>; | |||
//! \return bitwise xor (^) operation of its arguments. | |||
template <typename _Tp1, typename _Tp2> | |||
using bitxor_ = integral_c<decltype(_Tp1() ^ _Tp2()), _Tp1() ^ _Tp2()>; | |||
//! \return the result of bitwise shift left (<<) operation on _Tp. | |||
template <typename _Tp, typename shift> | |||
using shift_left = integral_c<decltype(_Tp() << shift()), (_Tp() << shift())>; | |||
//! \return the result of bitwise shift right (>>) operation on _Tp. | |||
template <typename _Tp, typename shift> | |||
using shift_right = integral_c<decltype(_Tp() >> shift()), (_Tp() >> shift())>; | |||
//! @} | |||
}} | |||
//!@} | |||
#endif /* __utl_meta_integral_h__ */ |
@@ -0,0 +1,74 @@ | |||
/*! | |||
* \file selection.h | |||
* \brief Template meta-programming type selections. | |||
* | |||
* 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/>. | |||
*/ | |||
#ifndef __utl_meta_selection_h__ | |||
#define __utl_meta_selection_h__ | |||
#include <utl/core/impl.h> | |||
#include <utl/meta/integral.h> | |||
#include <utl/meta/sfinae.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup type selection | |||
* Type selection support header | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta{ | |||
/*! | |||
* Type selection | |||
*/ | |||
//! @{ | |||
//! if_, if_c | |||
//! @{ | |||
namespace detail { | |||
template <bool If, typename...> | |||
struct if_c_ { | |||
using type = nil_; //!< avoid ill formed result | |||
}; | |||
template<typename Then> | |||
struct if_c_<true, Then> { | |||
using type = Then; | |||
}; | |||
template<typename Then, typename Else> | |||
struct if_c_<true, Then, Else> { | |||
using type = Then; | |||
}; | |||
template<typename Then, typename Else> | |||
struct if_c_<false, Then, Else> { | |||
using type = Else; | |||
}; | |||
} | |||
//! Select one type or another depending on a compile-time Boolean. | |||
template <bool B, typename... Args> | |||
using if_c = type_<detail::if_c_<B, Args...>>; | |||
//! Select one type or another depending on a compile-time Boolean type | |||
template <typename If, typename... Args> | |||
using if_ = if_c<If::type::value, Args...>; | |||
//! @} | |||
}} | |||
//! @} | |||
#endif /* __utl_meta_selection_h__ */ |
@@ -1,5 +1,5 @@ | |||
/*! | |||
* \file use.h | |||
* \file sfinae.h | |||
* \brief Template meta-programming SFINAE helpers | |||
* | |||
* Copyright (C) 2018 Christos Choutouridis | |||
@@ -17,72 +17,57 @@ | |||
* 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_use_h__ | |||
#define __utl_meta_use_h__ | |||
#include <utl/impl/impl.h> | |||
#include <utl/meta/logical.h> | |||
#ifndef __utl_meta_sfinae_h__ | |||
#define __utl_meta_sfinae_h__ | |||
#include <utl/core/impl.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup use | |||
* conditional use support header. This is a SFINAE helper | |||
* \defgroup sfinae | |||
* conditional use support header. | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta { | |||
/*! | |||
* void_t | |||
* Utility meta-function that maps a sequence of any types to the type void | |||
* \note The idea is: | |||
* template <typename ...> | |||
* using void_t = void; | |||
* | |||
* Until CWG 1558 (a C++14 defect), unused parameters in alias templates were not | |||
* guaranteed to ensure SFINAE and could be ignored, so earlier compilers require | |||
* a more complex definition of void_t, such as the following implementation | |||
* https://en.cppreference.com | |||
*/ | |||
//! Tool to enable a partial specialization only if a boolean condition is true. | |||
//! @{ | |||
template<typename... _Ts> | |||
struct void_t_impl { | |||
typedef void type; | |||
}; | |||
//! The actual void_t type alias | |||
template<typename... _Ts> | |||
using void_t = typename void_t_impl<_Ts...>::type; | |||
namespace detail { | |||
template <bool If> | |||
struct when_ { }; | |||
template <> struct when_<true> { using type = void; }; | |||
} | |||
//! Well formed only if \p If is true | |||
template <bool If> | |||
using when = type_<detail::when_<If>>; | |||
//! @} | |||
//! Alias template for if_ | |||
template<bool _Check, typename _Tp = void> | |||
using if_t = typename if_<_Check, _Tp>::type; | |||
//! Publicly recognized alias template for if_ | |||
template<bool _Check, typename _Tp = void> | |||
using enable_if_t = typename if_<_Check, _Tp>::type; | |||
//! Uniform alias template for if_ | |||
template<bool _Check, typename _Tp = void> | |||
using use_if_t = typename if_<_Check, _Tp>::type; | |||
//! If same type resolves to _Ret, else SFINAE | |||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||
using use_if_same_t = typename if_<same_<_T1, _T2>::value, _Ret>::type; | |||
//! select _Tp if \p If is true, else SFINAE | |||
//! We implement eneble_if so we don't have to pull entire \c <type_traits> from stl | |||
//! @{ | |||
template <bool If, typename _Tp = void> | |||
struct enable_if { | |||
using type = _Tp; | |||
}; | |||
template<typename _Tp> | |||
struct enable_if <false, _Tp> { /* SFINAE*/ }; | |||
//! If not same type resolves to _Ret, else SFINAE | |||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||
using use_if_not_same_t = typename if_<!same_<_T1, _T2>::value, _Ret>::type; | |||
//! Alias template for enable_if | |||
template <bool If, typename _Tp = void> | |||
using use_if = enable_if<If, _Tp>; | |||
//! 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 = typename if_<or_<_T1, _T2>::value, _Ret>::type; | |||
//! Publicly recognized alias template for enable_if | |||
template<bool If, typename _Tp = void> | |||
using enable_if_t = type_<enable_if<If, _Tp>>; | |||
//! 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 = typename if_<and_<_T1, _T2>::value, _Ret>::type; | |||
//! Uniform alias template for use_if | |||
template<bool If, typename _Tp = void> | |||
using use_if_t = type_<enable_if<If, _Tp>>; | |||
//! @} | |||
} | |||
}} | |||
//! @} | |||
#endif /* __utl_meta_use_h__ */ | |||
#endif /* __utl_meta_sfinae_h__ */ |
@@ -0,0 +1,420 @@ | |||
/*! | |||
* \file typelist.h | |||
* \brief A template parameter "container" | |||
* | |||
* 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/>. | |||
*/ | |||
#ifndef __utl_meta_pack_h__ | |||
#define __utl_meta_pack_h__ | |||
#include <utl/core/impl.h> | |||
#include <utl/meta/integral.h> | |||
#include <utl/meta/idx_sequence.h> | |||
#include <utl/meta/void.h> | |||
#include <utl/meta/utility.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup typelist | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta { | |||
/*! | |||
* A class template that just holds a parameter pack. | |||
* The idea came from MPL's sequence concept[1] and from N4115[2]. | |||
* In addition to N4115's name "packer" we just prefer a name which is object, not a subject. | |||
* This way the name gives the feeling of a container and smells like Python. | |||
* | |||
* In addition to tuple we lack members, so typelist could serve as an empty base class, | |||
* and an object of the ultimate type could always be instantiated | |||
* (even if the parameter typelist contains void or some type that lacks | |||
* a default constructor). | |||
* ex: | |||
* using l1 = typelist<int, void*, double>; | |||
* | |||
* boost::hana[3] suggest a more powerful scheme were type invariant structures can be used | |||
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the | |||
* responsibility that comse along). So a simple python-like list with some extra vector-like | |||
* element access functionalities and no iterators is good enough(for now). | |||
* | |||
* [1]: https://www.boost.org/doc/ | |||
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html | |||
* [3]: https://github.com/boostorg/hana | |||
*/ | |||
template <typename... Ts> | |||
struct typelist { | |||
using type = typelist; //!< act as identity | |||
//! \return sizeof...(Ts) | |||
static constexpr size_t size() noexcept { | |||
return sizeof...(Ts); | |||
} | |||
//! \return true if empty | |||
static constexpr bool empty() noexcept { | |||
return (sizeof...(Ts) == 0); | |||
} | |||
}; | |||
/*! | |||
* An integral constant wrapper that is the size of the \c meta::typelist | |||
* Complexity \f$ O(1) \f$. | |||
* \param List A typelist | |||
* \return The size of the typelist | |||
*/ | |||
template <typename List> | |||
using size = size_t_<List::size()>; | |||
/*! | |||
* An Boolean constant wrapper that returns if the typelist is empty | |||
* Complexity \f$ O(1) \f$. | |||
* \param List A typelist | |||
* \return Empty or not | |||
*/ | |||
template <typename List> | |||
using empty = bool_<List::empty()>; | |||
//! pair | |||
//! A special typelist with only 2 Types | |||
//! @{ | |||
template <typename T1, typename T2> | |||
using pair = typelist<T1, T2>; | |||
//! @} | |||
//! apply | |||
//! like: | |||
//! template <class F, class Tuple> | |||
//! constexpr decltype(auto) apply(F&& f, Tuple&& t); | |||
namespace detail { | |||
template <typename Fn, typename Param> | |||
struct apply_ { }; | |||
// apply Param =Ret(Args...) | |||
template <typename Fn, typename Ret, typename... Args> | |||
struct apply_<Fn, Ret(Args...)> | |||
: invoke<Fn, Ret, Args...> { }; | |||
// apply Param = F<Args...> | |||
template <typename Fn, template <typename...> class F, typename... Args> | |||
struct apply_<Fn, F<Args...>> | |||
: invoke<Fn, Args...> { }; | |||
// apply Param = integer_sequence<T, Is...> | |||
template <typename Fn, typename T, T... Is> | |||
struct apply_<Fn, integer_sequence<T, Is...>> | |||
: invoke<Fn, integral_constant<T, Is>...> { }; | |||
} | |||
//! Apply the Invocable \p Fn using the types in the type \p Param as arguments. | |||
template <typename Fn, typename Param> | |||
using apply = detail::apply_<Fn, Param>; | |||
//! @} | |||
/* | |||
* ========= typelist operations ========= | |||
*/ | |||
//! fold<List, V, Fn>, rev_fold<List, V, Fn> | |||
//! @{ | |||
namespace detail { | |||
// fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3> | |||
template<typename, typename, typename> | |||
struct fold_ { }; // ill formed | |||
// recursive call | |||
template<typename Head, typename... Tail, | |||
typename V, | |||
typename Fn> | |||
struct fold_<typelist<Head, Tail...>, V, Fn> { | |||
using type = type_< | |||
fold_< | |||
typelist<Tail...>, | |||
invoke<Fn, V, Head>, | |||
Fn | |||
> | |||
>; | |||
}; | |||
// termination call | |||
template<typename V0, typename Fn> | |||
struct fold_<typelist<>, V0, Fn> { | |||
using type = V0; | |||
}; | |||
// rev_fold<<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>> | |||
template<typename, typename, typename> | |||
struct rev_fold_ { }; // ill formed | |||
// recursive call | |||
template<typename Head, typename... Tail, | |||
typename V, | |||
typename Fn> | |||
struct rev_fold_<typelist<Head, Tail...>, V, Fn> { | |||
using type = invoke < | |||
Fn, Head, type_< | |||
rev_fold_ < | |||
typelist<Tail...>, | |||
V, | |||
Fn | |||
> | |||
> | |||
>; | |||
}; | |||
// termination call | |||
template<typename Tail, typename V, typename Fn> | |||
struct rev_fold_ <typelist<Tail>, V, Fn> { | |||
using type = invoke<Fn, Tail, V>; | |||
}; | |||
// termination call | |||
template<typename V, typename Fn> | |||
struct rev_fold_ <typelist<>, V, Fn> { | |||
using type = invoke<Fn, V>; | |||
}; | |||
} | |||
/*! | |||
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn | |||
* and initial value \p V | |||
* Complexity \f$ O(N) \f$ | |||
* \param List The list to fold | |||
* \param V The initial item feeded to Fn | |||
* \param Fn The binary Invocable | |||
*/ | |||
template <typename List, typename V, typename Fn> | |||
using fold = type_<detail::fold_<List, V, Fn>>; | |||
//! accumulate is an stl name for fold | |||
template <typename List, typename V, typename Fn> | |||
using accumulate = fold<List, V, Fn>; | |||
/*! | |||
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn | |||
* and initial value \p V | |||
* Complexity \f$ O(N) \f$ | |||
* \param List The list to fold | |||
* \param V The initial item feeded to Fn | |||
* \param Fn The binary Invocable | |||
*/ | |||
template <typename List, typename V, typename Fn> | |||
using rev_fold = type_<detail::rev_fold_<List, V, Fn>>; | |||
//! @} | |||
//! Concatenation | |||
//! @{ | |||
namespace detail { | |||
template <typename... Lists> | |||
struct concat_ { }; | |||
template <> | |||
struct concat_<> { | |||
using type = typelist<>; | |||
}; | |||
template <typename... L1> | |||
struct concat_<typelist<L1...>> { | |||
using type = typelist<L1...>; | |||
}; | |||
template <typename... L1, typename... L2> | |||
struct concat_<typelist<L1...>, typelist<L2...>> { | |||
using type = typelist<L1..., L2...>; | |||
}; | |||
template <typename... L1, typename... L2, typename... L3> | |||
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>> { | |||
using type = typelist<L1..., L2..., L3...>; | |||
}; | |||
template <typename... L1, typename... L2, typename... L3, typename... Rest> | |||
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, Rest...> | |||
: concat_<typelist<L1..., L2..., L3...>, Rest...> { }; | |||
template <typename... L1, typename... L2, | |||
typename... L3, typename... L4, | |||
typename... Rest> | |||
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, typelist<L4...>, Rest...> | |||
: concat_<typelist<L1..., L2..., L3..., L4...>, Rest...> { }; | |||
} | |||
/*! | |||
* Transformation that concatenates several lists into a single typelist. | |||
* The parameters must all be instantiations of \c meta::typelist. | |||
* Complexity: \f$ O(L) \f$ | |||
* where \f$ L \f$ is the number of lists in the typelist of lists. | |||
*/ | |||
template <typename... Lists> | |||
using concat = type_<detail::concat_<Lists...>>; | |||
//! @} | |||
//! Transform | |||
//! @{ | |||
namespace detail { | |||
template <typename, typename = void> | |||
struct transform_ { }; | |||
template <typename... Ts, typename Fn> | |||
struct transform_<typelist<typelist<Ts...>, Fn>, void_<invoke<Fn, Ts>...>> { | |||
using type = typelist<invoke<Fn, Ts>...>; | |||
}; | |||
template <typename... Ts0, typename... Ts1, typename Fn> | |||
struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>, | |||
void_<invoke<Fn, Ts0, Ts1>...>> { | |||
using type = typelist<invoke<Fn, Ts0, Ts1>...>; | |||
}; | |||
} // namespace detail | |||
/*! | |||
* Transform One or two lists with invocable \c Fn and return a new typelist | |||
* Syntax: | |||
* 1) transform<List..., Fn> Unary invocable | |||
* 2) transform<List1, List2, Fn> Binary invocable | |||
* Complexity \f$ O(N) \f$. | |||
*/ | |||
template <typename... Args> | |||
using transform = type_<detail::transform_<typelist<Args...>>>; | |||
//! @} | |||
//! repeat_n | |||
//! @{ | |||
namespace detail { | |||
template <typename T, size_t> | |||
using first_ = T; | |||
template <typename T, typename Ints> | |||
struct repeat_n_c_ { }; | |||
template <typename T, size_t... Is> | |||
struct repeat_n_c_<T, index_sequence<Is...>> { | |||
using type = typelist<first_<T, Is>...>; | |||
}; | |||
} | |||
/*! | |||
* Generate typelist<T,T,T...T> of size \c N arguments. | |||
* Complexity \f$ O(log N) \f$. | |||
*/ | |||
template <index_t N, typename T = void> | |||
using repeat_n_c = type_<detail::repeat_n_c_<T, make_index_sequence<N>>>; | |||
/*! | |||
* Generate typelist<T,T,T...T> of size \c N::type::value arguments. | |||
* Complexity \f$ O(log N) \f$. | |||
*/ | |||
template <typename N, typename T = void> | |||
using repeat_n = repeat_n_c<N::type::value, T>; | |||
//! @} | |||
//! at | |||
//! @{ | |||
namespace detail { | |||
template <typename VoidPtrs> | |||
struct at_impl_; | |||
template <typename... VoidPtrs> | |||
struct at_impl_<typelist<VoidPtrs...>> { | |||
static nil_ eval(...); | |||
template <typename T, typename... Us> | |||
static T eval(VoidPtrs..., T *, Us *...); | |||
}; | |||
template <typename L, index_t N> | |||
struct at_ { }; | |||
template <typename... Ts, index_t N> | |||
struct at_<typelist<Ts...>, N> | |||
: decltype( | |||
at_impl_<repeat_n_c<N, void *>>::eval(static_cast<identity<Ts> *>(nullptr)...) | |||
) { }; | |||
} // namespace detail | |||
/// Return the \p N th element in the \c meta::typelist \p L. | |||
/// Complexity \f$ O(1) \f$. | |||
template <typename L, index_t N> | |||
using at_c = type_<detail::at_<L, N>>; | |||
//! Return the \p N th element in the \c meta::typelist \p L. | |||
//! Complexity \f$ O(1) \f$. | |||
template <typename L, typename N> | |||
using at = at_c<L, N::type::value>; | |||
//!@} | |||
//! front | |||
//! @{ | |||
namespace detail { | |||
template <typename L> | |||
struct front_ { }; | |||
template <typename Head, typename... Tail> | |||
struct front_<typelist<Head, Tail...>> { | |||
using type = Head; | |||
}; | |||
} | |||
//! Return the first element in \c meta::typelist \p L. | |||
//! Complexity \f$ O(1) \f$. | |||
template <typename L> | |||
using front = type_<detail::front_<L>>; | |||
//! @} | |||
//! back | |||
//! @{ | |||
namespace detail { | |||
template <typename L> | |||
struct back_ { }; | |||
template <typename Head, typename... Tail> | |||
struct back_<typelist<Head, Tail...>> { | |||
using type = at_c<typelist<Head, Tail...>, sizeof...(Tail)>; | |||
}; | |||
} | |||
//! Return the last element in \c meta::typelist \p L. | |||
//! Complexity \f$ O(1) \f$. | |||
template <typename L> | |||
using back = type_<detail::back_<L>>; | |||
//! @} | |||
//! pop_front | |||
//! @{ | |||
namespace detail { | |||
template <typename L> | |||
struct pop_front_ { }; | |||
template <typename Head, typename... L> | |||
struct pop_front_<typelist<Head, L...>> { | |||
using type = typelist<L...>; | |||
}; | |||
} | |||
/*! | |||
* Return a new \c meta::typelist by removing the first element from the | |||
* front of \p L. | |||
* Complexity \f$ O(1) \f$. | |||
*/ | |||
template <typename L> | |||
using pop_front = type_<detail::pop_front_<L>>; | |||
//! @} | |||
}} | |||
//! @} | |||
#endif /* __utl_meta_pack_h__ */ |
@@ -0,0 +1,70 @@ | |||
/*! | |||
* \file useif.h | |||
* \brief Template meta-programming SFINAE helpers | |||
* | |||
* 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/>. | |||
*/ | |||
#ifndef __utl_meta_useif_h__ | |||
#define __utl_meta_useif_h__ | |||
#include <utl/core/impl.h> | |||
#include <utl/meta/logical.h> | |||
#include <utl/meta/sfinae.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup sfinae | |||
* conditional use support header. This is a SFINAE wrapper | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta { | |||
//! If same type resolves to _Ret, else SFINAE | |||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||
using use_if_same_t = type_< | |||
enable_if< | |||
same_<_T1, _T2>::value, _Ret | |||
> | |||
>; | |||
//! If not same type resolves to _Ret, else SFINAE | |||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||
using use_if_not_same_t = type_< | |||
enable_if< | |||
!same_<_T1, _T2>::value, _Ret | |||
> | |||
>; | |||
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE | |||
template <typename _T1, typename _T2, typename _Ret =_T1> | |||
using use_if_any_t = type_< | |||
enable_if< | |||
or_<_T1, _T2>::value, _Ret | |||
> | |||
>; | |||
//! 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 = type_< | |||
enable_if< | |||
and_<_T1, _T2>::value, _Ret | |||
> | |||
>; | |||
}} | |||
//! @} | |||
#endif /* __utl_meta_useif_h__ */ |
@@ -0,0 +1,246 @@ | |||
/*! | |||
* \file utility.h | |||
* \brief Template meta-programming utilities | |||
* | |||
* 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/>. | |||
*/ | |||
#ifndef __utl_meta_utility_h__ | |||
#define __utl_meta_utility_h__ | |||
#include <utl/core/impl.h> | |||
#include <utl/meta/integral.h> | |||
#include <utl/meta/void.h> | |||
#include <utl/meta/selection.h> | |||
/*! | |||
* \ingroup meta | |||
* \defgroup utility | |||
* | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta{ | |||
/*! | |||
* | |||
* \name invoke | |||
* All Metafunction classes shall contain apply, which is Metafunction | |||
* | |||
* Metafunction: | |||
* A metafunction is a class or a class template that represents a function invocable at compile-time. | |||
* An non-nullary metafunction is invoked by instantiating the class template with particular template | |||
* parameters (metafunction arguments). The result of the metafunction application is accessible | |||
* through the instantiation's nested type typedef. | |||
* All metafunction's arguments must be types (i.e. only type template parameters are allowed). | |||
* A metafunction can have a variable number of parameters. | |||
* A nullary metafunction is represented as a (template) class with a nested type typename member. | |||
* | |||
* Metafunction Class: | |||
* A metafunction class is a certain form of metafunction representation that enables higher-order | |||
* metaprogramming. More precisely, it's a class with a publicly-accessible nested Metafunction called | |||
* apply. Correspondingly, a metafunction class invocation is defined as invocation of its nested apply | |||
* metafunction. | |||
* | |||
* Concept here is `Invokable` (contains apply metafunction) | |||
*/ | |||
//! @{ | |||
/*! | |||
* *invocable* identity, identity_t. | |||
*/ | |||
//! @{ | |||
template <typename _Tp> | |||
struct identity { | |||
#if defined (UTL_WORKAROUND_CWG_1558) | |||
// decltype via use_() using Ts... to set the apply type | |||
template <typename... Ts> | |||
using _dummy = void_t<Ts...>; | |||
using apply = _Tp; //!< identity is invokable, must also have apply | |||
#else | |||
template <typename...> | |||
using apply = _Tp; //!< identity is invokable, must also have apply | |||
#endif | |||
using type = _Tp; //!< identity | |||
}; | |||
//! identity type alias | |||
template <typename _Tp> | |||
using identity_t = type_<identity<_Tp>>; | |||
//! @} | |||
//! Is evaluable trait | |||
//! @{ | |||
namespace detail { | |||
// we check for template \p F to be a metafunction with parameters \p T | |||
template<template<typename...> class F, typename... T> | |||
struct is_evaluable_ { | |||
template<template<typename...> class G, typename = G<T...>> | |||
static true_ check (int); | |||
template<template<typename...> class> | |||
static false_ check (...); | |||
using type = decltype(check<F>(0)); | |||
}; | |||
// we check for template \p F with integral constant parameters \p Is of type \p T | |||
// template<typename T, template <T...> class F, T... Is> | |||
// struct is_evaluable_i_ { | |||
// template<typename TT, template <TT...> class G, class = G<Is...>> | |||
// static true_ check (int); | |||
// template<typename, template<typename...> class> | |||
// static false_ check (...); | |||
// | |||
// using type = decltype(check<T, F>(0)); | |||
// }; | |||
} | |||
template<template<typename...> class F, typename... T> | |||
using is_evaluable = type_< | |||
detail::is_evaluable_<F, T...> | |||
>; | |||
// template <typename T, template<T...> class F, T... Is> | |||
// using is_evaluable_i = type_<detail::is_evaluable_i_<T, F<Is...>>>; | |||
//! @} | |||
//! defer | |||
//! @{ | |||
namespace detail { | |||
//! @{ | |||
template<template<typename...> class F, typename... Ts> | |||
struct defer_ { | |||
using type = F<Ts...>; | |||
}; | |||
// template<typename T, template<T...> class F, T... Is> | |||
// struct defer_i_ { | |||
// using type = F<Is...>; | |||
// }; | |||
//! | |||
//! We use struct instead of: | |||
//! template<template<typename...> class F, typename... Ts> | |||
//! using defer_ = F<Ts...>; | |||
//! | |||
//! The use of struct here is due to Core issue 1430 [1] and is used | |||
//! as suggested by Roy Crihfield in [2]. | |||
//! In short, this is due to language's inability to expand Ts... into | |||
//! a fixed parameter list of an alias template. | |||
//! | |||
//! [1]: https://wg21.link/cwg1430 | |||
//! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498 | |||
//! @} | |||
} | |||
//! defer alias template for F<Ts...> | |||
template<template<class...> class F, class... Ts> | |||
using defer = if_< | |||
is_evaluable<F, Ts...>, | |||
detail::defer_<F, Ts...>, | |||
nil_ | |||
>; | |||
//! defer_i alias template for F<T, Is...> | |||
// template <typename T, template<T...> class F, T... Is> | |||
// using defer_i = if_ < | |||
// is_evaluable_i<T, F<Is...>>, | |||
// detail::defer_i_<F, Is...>, | |||
// nil_ | |||
// >; | |||
//! @} | |||
/*! | |||
* quote is a higher-order primitive that wraps an n-ary Metafunction | |||
* to create a corresponding Metafunction Class (Invocable). | |||
*/ | |||
template <template <typename...> class F> | |||
struct quote { | |||
template <typename... Args> | |||
using apply = type_<defer<F, Args...>>; //!< defer here to avoid DR1430 | |||
}; | |||
//! Wrap a template \p F taking literals of type \p T into an Invokable | |||
// template <typename T, template <T...> class F> | |||
// struct quote_i { | |||
// // requires meta::Integral | |||
// template <typename... Is> | |||
// using apply = type_< | |||
// defer_i<T, F, Is...> //!< defer here to avoid DR1430 | |||
// >; | |||
// }; | |||
/*! | |||
* Invoke the nested apply metafunction from \c Fn | |||
* with the arguments \c Args. | |||
* requires Invocable(Fn) | |||
*/ | |||
template <typename Fn, typename... Args> | |||
using invoke = typename Fn::template apply<Args...>; | |||
//! compose | |||
//! @{ | |||
namespace detail { | |||
template<typename ...Fns> struct compose_ { }; | |||
// recursive call to all invokes | |||
template<typename Fn0, typename ...Fns> | |||
struct compose_<Fn0, Fns...> { | |||
template <typename ...Args> | |||
using apply = invoke< | |||
Fn0, | |||
invoke<compose_<Fns...>, Args...> | |||
>; | |||
}; | |||
// Termination specialization, finally pass the arguments | |||
template<typename Fn0> | |||
struct compose_<Fn0> { | |||
template <typename... Args> | |||
using apply = invoke<Fn0, Args...>; | |||
}; | |||
} | |||
/*! | |||
* Create an invokable from other invokables by composition | |||
* ex: | |||
* compose<Fns...> will result to something like F0<F1<F2<F3<...>>>> | |||
*/ | |||
template <typename... Fns> | |||
using compose = detail::compose_<Fns...>; | |||
//! @} | |||
//! Applies the Invocable \p Fn by binding the arguments \p Ts | |||
//! to the \e front of \p Fn. | |||
template<typename Fn, typename... Ts> | |||
struct bind_front { | |||
template<typename... Us> | |||
using apply = invoke<Fn, Ts..., Us...>; | |||
}; | |||
//! Applies the Invocable \p Fn by binding the arguments \p Ts | |||
//! to the \e back of \p Fn. | |||
template<typename Fn, typename... Ts> | |||
struct bind_back { | |||
template<typename... Us> | |||
using apply = invoke<Fn, Us..., Ts...>; | |||
}; | |||
//! @} | |||
}} | |||
//! @} | |||
#endif /* __utl_meta_utility_h__ */ |
@@ -1,6 +1,6 @@ | |||
/*! | |||
* \file void.h | |||
* \brief Template meta-programming void helpers | |||
* \brief void_t meta-function | |||
* | |||
* Copyright (C) 2018 Christos Choutouridis | |||
* | |||
@@ -20,44 +20,37 @@ | |||
#ifndef __utl_meta_void_h__ | |||
#define __utl_meta_void_h__ | |||
#include <utl/impl/impl.h> | |||
#include <utl/meta/bool.h> | |||
#include <utl/core/impl.h> | |||
/*! \ingroup meta | |||
/*! | |||
* \ingroup meta | |||
* \defgroup void | |||
* void_ support header | |||
*/ | |||
//! @{ | |||
namespace utl { | |||
namespace meta { | |||
/*! | |||
* Like boost::mpl we made void_ a complete type to allow it to be | |||
* instantiated so that it can be passed in as an object that can be | |||
* used to select an overloaded function. | |||
* void_t meta-function that maps a sequence of any types to the type void | |||
*/ | |||
struct void_ { | |||
typedef void_ type; | |||
}; | |||
template<typename _Tp> | |||
struct is_void_ | |||
: false_ { }; | |||
template<> | |||
struct is_void_ <void_> | |||
: true_ { }; | |||
template<typename _Tp> | |||
struct is_not_void_ | |||
: true_ { }; | |||
template<> | |||
struct is_not_void_<void_> | |||
: false_ { }; | |||
} | |||
//! @{ | |||
#if defined(UTL_WORKAROUND_CWG_1558) | |||
template<typename... _Ts> | |||
struct void_ { | |||
using type = void; | |||
}; | |||
//! void_t type alias | |||
template<typename... _Ts> | |||
using void_t = type_of<void_<_Ts...>>; | |||
#else | |||
//! void_ type alias | |||
template <typename...> using void_ = void; | |||
//! void_t type alias | |||
template <typename...> using void_t = void; | |||
#endif | |||
//! @} | |||
}} | |||
//!@} | |||
#endif /* __utl_meta_void_h__ */ |