!compile: Some meta:: rework
This commit is contained in:
parent
19f6991a83
commit
031349a44d
113
include/utl/meta/idx_sequence.h
Normal file
113
include/utl/meta/idx_sequence.h
Normal file
@ -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__ */
|
||||
|
63
include/utl/meta/invoke.h
Normal file
63
include/utl/meta/invoke.h
Normal file
@ -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...>
|
||||
: select_<_T1::value, _T1, or_<_T2, _T3, _Tn...>> { };
|
||||
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_ = 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...>
|
||||
: select_<_T1::value, and_<_T2, _T3, _Tn...>, _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_ = type_<detail::_and_<_Ts...>>;
|
||||
//! @}
|
||||
|
||||
//! same
|
||||
@ -90,11 +107,12 @@ namespace utl {
|
||||
//! not same
|
||||
//! @{
|
||||
template<typename _T1, typename _T2>
|
||||
struct not_same_ : true_ { };
|
||||
|
||||
template<typename _Tp>
|
||||
struct not_same_ <_Tp, _Tp> : false_ { };
|
||||
using not_same_ = not_<type_<same_<_T1, _T2>>>;
|
||||
//! @}
|
||||
}
|
||||
|
||||
//! @}
|
||||
}}
|
||||
|
||||
//! @}
|
||||
|
||||
#endif /* __utl_meta_logical_h__ */
|
||||
|
33
include/utl/meta/meta.h
Normal file
33
include/utl/meta/meta.h
Normal file
@ -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__ */
|
132
include/utl/meta/operations.h
Normal file
132
include/utl/meta/operations.h
Normal file
@ -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__ */
|
74
include/utl/meta/selection.h
Normal file
74
include/utl/meta/selection.h
Normal file
@ -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;
|
||||
//! 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*/ };
|
||||
|
||||
//! Publicly recognized alias template for if_
|
||||
template<bool _Check, typename _Tp = void>
|
||||
using enable_if_t = typename if_<_Check, _Tp>::type;
|
||||
//! Alias template for enable_if
|
||||
template <bool If, typename _Tp = void>
|
||||
using use_if = enable_if<If, _Tp>;
|
||||
|
||||
//! Uniform alias template for if_
|
||||
template<bool _Check, typename _Tp = void>
|
||||
using use_if_t = typename if_<_Check, _Tp>::type;
|
||||
//! Publicly recognized alias template for enable_if
|
||||
template<bool If, typename _Tp = void>
|
||||
using enable_if_t = type_<enable_if<If, _Tp>>;
|
||||
|
||||
//! 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;
|
||||
//! Uniform alias template for use_if
|
||||
template<bool If, typename _Tp = void>
|
||||
using use_if_t = type_<enable_if<If, _Tp>>;
|
||||
//! @}
|
||||
|
||||
//! 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;
|
||||
|
||||
//! 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;
|
||||
|
||||
//! 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;
|
||||
|
||||
}
|
||||
}}
|
||||
|
||||
//! @}
|
||||
#endif /* __utl_meta_use_h__ */
|
||||
|
||||
#endif /* __utl_meta_sfinae_h__ */
|
||||
|
420
include/utl/meta/typelist.h
Normal file
420
include/utl/meta/typelist.h
Normal file
@ -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__ */
|
70
include/utl/meta/useif.h
Normal file
70
include/utl/meta/useif.h
Normal file
@ -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__ */
|
246
include/utl/meta/utility.h
Normal file
246
include/utl/meta/utility.h
Normal file
@ -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__ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user