Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19d1fc6890 | ||
|
|
a436935d89 | ||
|
|
fa431d5be7 | ||
|
|
d1242f969c | ||
|
|
ef5eb2c891 | ||
|
|
d076b4ae38 |
@@ -397,7 +397,7 @@ INLINE_GROUPED_CLASSES = NO
|
|||||||
# Man pages) or section (for LaTeX and RTF).
|
# Man pages) or section (for LaTeX and RTF).
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
INLINE_SIMPLE_STRUCTS = YES
|
INLINE_SIMPLE_STRUCTS = NO
|
||||||
|
|
||||||
# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
|
# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
|
||||||
# enum is documented as struct, union, or enum with the name of the typedef. So
|
# enum is documented as struct, union, or enum with the name of the typedef. So
|
||||||
@@ -570,7 +570,7 @@ INLINE_INFO = YES
|
|||||||
# name. If set to NO, the members will appear in declaration order.
|
# name. If set to NO, the members will appear in declaration order.
|
||||||
# The default value is: YES.
|
# The default value is: YES.
|
||||||
|
|
||||||
SORT_MEMBER_DOCS = YES
|
SORT_MEMBER_DOCS = NO
|
||||||
|
|
||||||
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
|
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
|
||||||
# descriptions of file, namespace and class members alphabetically by member
|
# descriptions of file, namespace and class members alphabetically by member
|
||||||
@@ -607,7 +607,7 @@ SORT_GROUP_NAMES = NO
|
|||||||
# list.
|
# list.
|
||||||
# The default value is: NO.
|
# The default value is: NO.
|
||||||
|
|
||||||
SORT_BY_SCOPE_NAME = YES
|
SORT_BY_SCOPE_NAME = NO
|
||||||
|
|
||||||
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
|
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
|
||||||
# type resolution of all parameters of a function it will reject a match between
|
# type resolution of all parameters of a function it will reject a match between
|
||||||
@@ -873,7 +873,11 @@ RECURSIVE = YES
|
|||||||
# Note that relative paths are relative to the directory from which doxygen is
|
# Note that relative paths are relative to the directory from which doxygen is
|
||||||
# run.
|
# run.
|
||||||
|
|
||||||
EXCLUDE = test
|
EXCLUDE = test \
|
||||||
|
include/utl/dev \
|
||||||
|
include/utl/concepts \
|
||||||
|
include/utl/com \
|
||||||
|
include/utl/container
|
||||||
|
|
||||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||||
@@ -1087,7 +1091,7 @@ CLANG_ASSISTED_PARSING = YES
|
|||||||
# specified with INPUT and INCLUDE_PATH.
|
# specified with INPUT and INCLUDE_PATH.
|
||||||
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||||
|
|
||||||
CLANG_OPTIONS = -I../include
|
CLANG_OPTIONS = -std=c++14
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the alphabetical class index
|
# Configuration options related to the alphabetical class index
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#ifndef __utl_concepts_concepts_h__
|
#ifndef __utl_concepts_concepts_h__
|
||||||
#define __utl_consepts_concepts_h__
|
#define __utl_concepts_concepts_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace utl {
|
|||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename _T1, typename _T2, typename _Ret =_T1>
|
||||||
using use_if_same_t = meta::eval<
|
using use_if_same_t = meta::eval<
|
||||||
meta::enable_if<
|
meta::enable_if<
|
||||||
meta::same_<_T1, _T2>::value, _Ret
|
meta::same<_T1, _T2>::value, _Ret
|
||||||
>
|
>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ namespace utl {
|
|||||||
* Same
|
* Same
|
||||||
*/
|
*/
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
_utlConcept Same = meta::same_<T, U>::value;
|
_utlConcept Same = meta::same<T, U>::value;
|
||||||
|
|
||||||
// template<class T>
|
// template<class T>
|
||||||
// _utlConcept Decayed = Same<T, std::decay_t<T>>;
|
// _utlConcept Decayed = Same<T, std::decay_t<T>>;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*!
|
/*!
|
||||||
* \file utl/impl/crtp.h
|
* \file utl/core/crtp.h
|
||||||
* \brief CRTP idiom support header
|
* \brief CRTP idiom support header
|
||||||
*/
|
*/
|
||||||
#ifndef __utl_impl_crtp_h__
|
#ifndef __utl_impl_crtp_h__
|
||||||
@@ -13,8 +13,10 @@
|
|||||||
*
|
*
|
||||||
* utl supports both CRTP idiom and dynamic polymorphism. By default
|
* utl supports both CRTP idiom and dynamic polymorphism. By default
|
||||||
* CRTP is the preferred way. If the user need virtuals then instead of
|
* CRTP is the preferred way. If the user need virtuals then instead of
|
||||||
* CRTP type, the \ref virtual_tag can passed to base class. The rest
|
* CRTP type, the \c virtual_tag can passed to base class. The rest
|
||||||
* will handled by utl automatically.
|
* will handled by utl automatically.
|
||||||
|
*
|
||||||
|
* \sa utl::virtual_tag
|
||||||
*/
|
*/
|
||||||
//!@{
|
//!@{
|
||||||
namespace utl {
|
namespace utl {
|
||||||
@@ -25,8 +27,8 @@ namespace utl {
|
|||||||
|
|
||||||
//! \def CRTP boilerplate lines
|
//! \def CRTP boilerplate lines
|
||||||
#define _CRTP_IMPL(T) \
|
#define _CRTP_IMPL(T) \
|
||||||
constexpr T& impl() { return *static_cast<T*>(this); } \
|
constexpr T& impl() { return *static_cast<T*>(this); } \
|
||||||
constexpr const T& impl() const { return *static_cast<const T*>(this); }
|
constexpr const T& impl() const { return *static_cast<const T*>(this); }
|
||||||
|
|
||||||
}
|
}
|
||||||
//!@}
|
//!@}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
//!
|
//!
|
||||||
//! This can be used in the user files to check for uTL versions.
|
//! This can be used in the user files to check for uTL versions.
|
||||||
//! The version number is constructed using:\n
|
//! The version number is constructed using:\n
|
||||||
//! ver = (Maj*10000 + Min*100 + Patch)
|
//! \f$ ver = (Maj*10000 + Min*100 + Patch) \f$
|
||||||
#define UTL_VERSION_VALUE ( (UTL_VERSION_MAJOR * 10000) \
|
#define UTL_VERSION_VALUE ( (UTL_VERSION_MAJOR * 10000) \
|
||||||
+ (UTL_VERSION_MINOR * 100) \
|
+ (UTL_VERSION_MINOR * 100) \
|
||||||
+ UTL_VERSION_PATCH)
|
+ UTL_VERSION_PATCH)
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ namespace utl {
|
|||||||
typename T::difference_type;
|
typename T::difference_type;
|
||||||
typename T::pointer;
|
typename T::pointer;
|
||||||
typename T::reference;
|
typename T::reference;
|
||||||
requires same_<
|
requires same<
|
||||||
typename T::iterator_category,
|
typename T::iterator_category,
|
||||||
std::output_iterator_tag
|
std::output_iterator_tag
|
||||||
>::value;
|
>::value;
|
||||||
@@ -675,7 +675,7 @@ namespace utl {
|
|||||||
typename T::difference_type;
|
typename T::difference_type;
|
||||||
typename T::pointer;
|
typename T::pointer;
|
||||||
typename T::reference;
|
typename T::reference;
|
||||||
requires same_ <
|
requires same <
|
||||||
typename T::iterator_category,
|
typename T::iterator_category,
|
||||||
std::input_iterator_tag
|
std::input_iterator_tag
|
||||||
>::value;
|
>::value;
|
||||||
@@ -960,7 +960,7 @@ namespace utl {
|
|||||||
typename T::difference_type;
|
typename T::difference_type;
|
||||||
typename T::pointer;
|
typename T::pointer;
|
||||||
typename T::reference;
|
typename T::reference;
|
||||||
requires same_<
|
requires same<
|
||||||
typename T::iterator_category,
|
typename T::iterator_category,
|
||||||
std::input_iterator_tag
|
std::input_iterator_tag
|
||||||
>::value;
|
>::value;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace utl {
|
|||||||
namespace meta {
|
namespace meta {
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* meta's empty type
|
* \brief meta's empty type
|
||||||
*
|
*
|
||||||
* utl::meta's nil type is not pure nil. It's a recursive "de-referencable nil.
|
* utl::meta's nil type is not pure nil. It's a recursive "de-referencable nil.
|
||||||
* Each time someone applies \c \::type to it, he gets back nil_. This way we can prevent
|
* Each time someone applies \c \::type to it, he gets back nil_. This way we can prevent
|
||||||
@@ -292,13 +292,13 @@ namespace meta{
|
|||||||
//! \name same
|
//! \name same
|
||||||
//! @{
|
//! @{
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
struct same_ : false_ { };
|
struct same : false_ { };
|
||||||
|
|
||||||
template<typename Tp>
|
template<typename Tp>
|
||||||
struct same_ <Tp, Tp> : true_ { };
|
struct same <Tp, Tp> : true_ { };
|
||||||
|
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
using not_same_ = not_<eval<same_<T1, T2>>>;
|
using not_same = not_<eval<same<T1, T2>>>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|||||||
@@ -40,8 +40,10 @@ namespace meta {
|
|||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Not a type to use in detected idiom. This type can
|
* \brief
|
||||||
* not be constructed, destructed or copied.
|
* Not a type to use in detected idiom.
|
||||||
|
*
|
||||||
|
* This type can not be constructed, destructed or copied.
|
||||||
*/
|
*/
|
||||||
struct nat_ {
|
struct nat_ {
|
||||||
nat_() = delete;
|
nat_() = delete;
|
||||||
@@ -177,7 +179,7 @@ namespace meta {
|
|||||||
template <typename Expected,
|
template <typename Expected,
|
||||||
template<typename...> class Op, typename... Args >
|
template<typename...> class Op, typename... Args >
|
||||||
using is_detected_exact = eval <
|
using is_detected_exact = eval <
|
||||||
same_<Expected, detected_t<Op, Args...>>
|
same<Expected, detected_t<Op, Args...>>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
|
//! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
|
||||||
|
|||||||
+117
-36
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
* \defgroup invoke Invoke
|
* \defgroup meta_invoke Invoke
|
||||||
* A meta-programming invoke() analogous.
|
* A meta-programming invoke() analogous.
|
||||||
*
|
*
|
||||||
* This module provides <b>higher order</b> tools to meta. utl::meta's metafunctions inputs are types.
|
* This module provides <b>higher order</b> tools to meta. utl::meta's metafunctions inputs are types.
|
||||||
@@ -39,22 +39,22 @@ namespace meta{
|
|||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
//! Identity is a metafunction always return the input type
|
//! Identity is a metafunction always return the input type
|
||||||
template <typename _Tp>
|
template <typename Tp>
|
||||||
struct identity {
|
struct identity {
|
||||||
#if defined (UTL_WORKAROUND_CWG_1558)
|
#if defined (UTL_WORKAROUND_CWG_1558)
|
||||||
// redirect unused Ts... via void_t
|
// redirect unused Ts... via void_t
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
using apply = first_of<_Tp, void_t<Ts...>>; //!< identity is invokable, must also have apply
|
using apply = first_of<Tp, void_t<Ts...>>; //!< identity is invokable, must also have apply
|
||||||
#else
|
#else
|
||||||
template <typename...>
|
template <typename...>
|
||||||
using apply = _Tp; //!< identity is invokable, must also have apply
|
using apply = Tp; //!< identity is invokable, must also have apply
|
||||||
#endif
|
#endif
|
||||||
using type = _Tp; //!< identity
|
using type = Tp; //!< identity
|
||||||
};
|
};
|
||||||
|
|
||||||
//! identity type alias
|
//! identity type alias
|
||||||
template <typename _Tp>
|
template <typename Tp>
|
||||||
using identity_t = eval<identity<_Tp>>;
|
using identity_t = eval<identity<Tp>>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -79,11 +79,17 @@ namespace meta{
|
|||||||
|
|
||||||
//! \name wrap
|
//! \name wrap
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Wraps an n-ary Metafunction \c F to a Metafunction Class
|
||||||
|
*
|
||||||
* wrap is a higher-order primitive that wraps an n-ary Metafunction
|
* wrap is a higher-order primitive that wraps an n-ary Metafunction
|
||||||
* to create a corresponding Metafunction Class (Invocable). This way
|
* to create a corresponding Metafunction Class (Invocable). This way
|
||||||
* we can pass Metafunctions as types to other metafunctions and let
|
* we can pass Metafunctions as types to other metafunctions and let
|
||||||
* them \c invoke the inner templated apply
|
* them \c invoke the inner templated apply.
|
||||||
|
*
|
||||||
|
* \tparam F The metafunction to wrap
|
||||||
*/
|
*/
|
||||||
template <template <typename...> class F>
|
template <template <typename...> class F>
|
||||||
struct wrap {
|
struct wrap {
|
||||||
@@ -91,7 +97,19 @@ namespace meta{
|
|||||||
using apply = F<Args...>;
|
using apply = F<Args...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Wraps an n-ary Metafunction \c F taking literal constants of type \c T
|
||||||
|
* to a Metafunction Class
|
||||||
|
*
|
||||||
|
* wrap_i is a higher-order primitive that wraps an n-ary Metafunction
|
||||||
|
* to create a corresponding Metafunction Class (Invocable).
|
||||||
|
* This way we can pass Metafunctions as types to other metafunctions and let
|
||||||
|
* them \c invoke the inner templated apply.
|
||||||
|
*
|
||||||
|
* \tparam T Type of integral constants
|
||||||
|
* \tparam F The metafunction to wrap
|
||||||
|
*/
|
||||||
template <typename T, template <T...> class F>
|
template <typename T, template <T...> class F>
|
||||||
struct wrap_i {
|
struct wrap_i {
|
||||||
// requires meta::Integral
|
// requires meta::Integral
|
||||||
@@ -122,7 +140,7 @@ namespace meta{
|
|||||||
static nil_ check (...); //< all other combinations
|
static nil_ check (...); //< all other combinations
|
||||||
|
|
||||||
using type = if_ <
|
using type = if_ <
|
||||||
not_same_<
|
not_same<
|
||||||
nil_,
|
nil_,
|
||||||
decltype(check<F>(0))
|
decltype(check<F>(0))
|
||||||
>, true_, false_
|
>, true_, false_
|
||||||
@@ -145,18 +163,41 @@ namespace meta{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//! check if we can instantiate \p F with parameters \p T
|
/*!
|
||||||
template<template<typename...> class F, typename... T>
|
* \brief
|
||||||
|
* Check if we can instantiate metafunction \c F with parameters \p Ts
|
||||||
|
*
|
||||||
|
* \tparam F The metafunction
|
||||||
|
* \tparam Ts The parameters to \c F
|
||||||
|
*/
|
||||||
|
template<template<typename...> class F, typename... Ts>
|
||||||
using is_applicable_t = eval<
|
using is_applicable_t = eval<
|
||||||
details::is_applicable_<F, T...>
|
details::is_applicable_<F, Ts...>
|
||||||
>;
|
|
||||||
//! check if we can invoke \p Q with parameters \p T
|
|
||||||
template<typename Q, typename... T>
|
|
||||||
using is_applicable_qt = eval <
|
|
||||||
details::is_applicable_q_ <Q, T...>
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! check if we can instantiate \p F with parameters \p Is of type \p T
|
|
||||||
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Check if we can invoke the quoted metafunction \c Q with parameters \p Ts
|
||||||
|
*
|
||||||
|
* \tparam Q The quoted metafunction
|
||||||
|
* \tparam Ts The parameters to \c Q
|
||||||
|
*
|
||||||
|
* \sa utl::meta::quote
|
||||||
|
*/
|
||||||
|
template<typename Q, typename... Ts>
|
||||||
|
using is_applicable_qt = eval <
|
||||||
|
details::is_applicable_q_ <Q, Ts...>
|
||||||
|
>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Check if we can instantiate metafunction \c F with parameters \p Is of type \c T
|
||||||
|
*
|
||||||
|
* \tparam T The type of \c Is
|
||||||
|
* \tparam F The metafunction
|
||||||
|
* \tparam Is The parameters to \c F
|
||||||
|
*/
|
||||||
template <typename T, template<T...> class F, T... Is>
|
template <typename T, template<T...> class F, T... Is>
|
||||||
using is_applicable_it = eval<
|
using is_applicable_it = eval<
|
||||||
details::is_applicable_i_<T, F, Is...>
|
details::is_applicable_i_<T, F, Is...>
|
||||||
@@ -182,16 +223,25 @@ namespace meta{
|
|||||||
//! template<template<typename...> class F, typename... Ts>
|
//! template<template<typename...> class F, typename... Ts>
|
||||||
//! using defer_ = F<Ts...>;
|
//! using defer_ = F<Ts...>;
|
||||||
//!
|
//!
|
||||||
//! The use of struct here is due to Core issue 1430 \ref link1 and is used
|
//! The use of struct here is due to Core issue 1430 [1] and is used
|
||||||
//! as suggested by Roy Crihfield in \ref link2.
|
//! as suggested by Roy Crihfield in [2].
|
||||||
//! In short, this is due to language's inability to expand Ts... into
|
//! In short, this is due to language's inability to expand Ts... into
|
||||||
//! a fixed parameter list of an alias template.
|
//! a fixed parameter list of an alias template.
|
||||||
//!
|
//!
|
||||||
//! \anchor link1 https://wg21.link/cwg1430
|
//! [1] https://wg21.link/cwg1430\n
|
||||||
//! \anchor link2 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
|
//! [2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
|
||||||
}
|
}
|
||||||
|
|
||||||
//! defer alias template for F<Ts...>
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Postpone the instantiation of a metafunction \c F with parameters \c Ts
|
||||||
|
*
|
||||||
|
* This metafunction first checks if the given arguments \c Ts are applicable to
|
||||||
|
* the metafunction \c F and if so nest inside (a layer deeper) the <em>metafunction call</em>.
|
||||||
|
*
|
||||||
|
* \tparam F The metafunction
|
||||||
|
* \tparam Ts The parameters (arguments) to \c F
|
||||||
|
*/
|
||||||
template<template<class...> class F, class... Ts>
|
template<template<class...> class F, class... Ts>
|
||||||
using defer = if_<
|
using defer = if_<
|
||||||
details::is_applicable_<F, Ts...>,
|
details::is_applicable_<F, Ts...>,
|
||||||
@@ -199,7 +249,17 @@ namespace meta{
|
|||||||
nil_ //!< Safe, nil_ is dereferencable
|
nil_ //!< Safe, nil_ is dereferencable
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! defer_i alias template for F<T, Is...>
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Postpone the instantiation of a metafunction \c F with parameters \c Is of type \c T.
|
||||||
|
*
|
||||||
|
* This metafunction first checks if the given arguments \c Is of type \c T are applicable to
|
||||||
|
* the metafunction \c F and if so nest inside (a layer deeper) the <em>metafunction call</em>.
|
||||||
|
*
|
||||||
|
* \tparam T The type of parameters
|
||||||
|
* \tparam F The metafunction
|
||||||
|
* \tparam Is The parameters (arguments) to \c F
|
||||||
|
*/
|
||||||
template <typename T, template<T...> class F, T... Is>
|
template <typename T, template<T...> class F, T... Is>
|
||||||
using defer_i = if_ <
|
using defer_i = if_ <
|
||||||
details::is_applicable_i_<T, F, Is...>,
|
details::is_applicable_i_<T, F, Is...>,
|
||||||
@@ -211,11 +271,16 @@ namespace meta{
|
|||||||
//! \name quote
|
//! \name quote
|
||||||
//! @{
|
//! @{
|
||||||
/*!
|
/*!
|
||||||
* quote deferred is a higher-order primitive that wraps an n-ary Metafunction
|
* \brief
|
||||||
|
* Wraps an n-ary Metafunction \c F to a Metafunction Class using meta::defer<>
|
||||||
|
*
|
||||||
|
* quote is a higher-order primitive that wraps an n-ary Metafunction
|
||||||
* to create a corresponding Metafunction Class (Invocable) using defer<> to
|
* to create a corresponding Metafunction Class (Invocable) using defer<> to
|
||||||
* postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.
|
* postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.\n
|
||||||
* Again this way we can pass Metafunctions as types to other metafunctions and let
|
* Again this way we can pass Metafunctions as types to other metafunctions and let
|
||||||
* them \c invoke the inner templated apply
|
* them \c invoke the inner templated apply
|
||||||
|
*
|
||||||
|
* \tparam F The metafunction to wrap
|
||||||
*/
|
*/
|
||||||
template <template <typename...> class F>
|
template <template <typename...> class F>
|
||||||
struct quote {
|
struct quote {
|
||||||
@@ -225,7 +290,21 @@ namespace meta{
|
|||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Wrap a template \p F taking literal constants of type \p T into an Invokable
|
|
||||||
|
/*!
|
||||||
|
* \brief
|
||||||
|
* Wraps an n-ary Metafunction \c F taking literal constants of type \c T
|
||||||
|
* to a Metafunction Class using meta::defer<>
|
||||||
|
*
|
||||||
|
* quote is a higher-order primitive that wraps an n-ary Metafunction
|
||||||
|
* to create a corresponding Metafunction Class (Invocable) using defer<> to
|
||||||
|
* postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.\n
|
||||||
|
* Again this way we can pass Metafunctions as types to other metafunctions and let
|
||||||
|
* them \c invoke the inner templated apply
|
||||||
|
*
|
||||||
|
* \tparam T Type of integral constants
|
||||||
|
* \tparam F The metafunction to wrap
|
||||||
|
*/
|
||||||
template <typename T, template <T...> class F>
|
template <typename T, template <T...> class F>
|
||||||
struct quote_i {
|
struct quote_i {
|
||||||
// requires meta::Integral
|
// requires meta::Integral
|
||||||
@@ -279,7 +358,8 @@ namespace meta{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Create an invocable from other invocables(quoted metafunctions) by composition.
|
* \brief
|
||||||
|
* Create an invocable from other invocables(quoted metafunctions) by composition.
|
||||||
* \note
|
* \note
|
||||||
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
||||||
* Thats because of the "return" type of metafunction. They can only return one
|
* Thats because of the "return" type of metafunction. They can only return one
|
||||||
@@ -295,7 +375,8 @@ namespace meta{
|
|||||||
using compose = details::compose_<Fns...>;
|
using compose = details::compose_<Fns...>;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Create an invocable from other metafunctions by composition.
|
* \brief
|
||||||
|
* Create an invocable from other metafunctions by composition.
|
||||||
* \note
|
* \note
|
||||||
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
* This implies from N invocables in \p Fns the first N-1 has to be unary.
|
||||||
* Thats because of the "return" type of metafunction. They can only return one
|
* Thats because of the "return" type of metafunction. They can only return one
|
||||||
@@ -312,8 +393,8 @@ namespace meta{
|
|||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Applies the invocable \p Fn by binding the arguments \p Ts
|
* \brief
|
||||||
* to the front of \p Fn.
|
* Applies the invocable \p Fn by binding the arguments \p Ts to the front of \p Fn.
|
||||||
*/
|
*/
|
||||||
template<typename Fn, typename... Ts>
|
template<typename Fn, typename... Ts>
|
||||||
struct bind_front {
|
struct bind_front {
|
||||||
@@ -322,8 +403,8 @@ namespace meta{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Applies the Invocable \p Fn by binding the arguments \p Ts
|
* \brief
|
||||||
* to the back of \p Fn.
|
* Applies the Invocable \p Fn by binding the arguments \p Ts to the back of \p Fn.
|
||||||
*/
|
*/
|
||||||
template<typename Fn, typename... Ts>
|
template<typename Fn, typename... Ts>
|
||||||
struct bind_back {
|
struct bind_back {
|
||||||
@@ -338,13 +419,13 @@ namespace meta{
|
|||||||
template <typename T1>
|
template <typename T1>
|
||||||
struct same_as {
|
struct same_as {
|
||||||
template <typename T2>
|
template <typename T2>
|
||||||
struct apply : same_<T1, T2> { };
|
struct apply : same<T1, T2> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T1>
|
template <typename T1>
|
||||||
struct not_same_as {
|
struct not_same_as {
|
||||||
template <typename T2>
|
template <typename T2>
|
||||||
struct apply : not_same_<T1, T2> { };
|
struct apply : not_same<T1, T2> { };
|
||||||
};
|
};
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|||||||
+12
-7
@@ -10,22 +10,27 @@
|
|||||||
*
|
*
|
||||||
* uTL::meta is a simple metaprogramming library used widely inside uTL.
|
* uTL::meta is a simple metaprogramming library used widely inside uTL.
|
||||||
* The lib is provided to the end user via namespace \c utl::meta
|
* The lib is provided to the end user via namespace \c utl::meta
|
||||||
* The library consist of:
|
* The library assembles:
|
||||||
*
|
*
|
||||||
* - integral constant based, operation and arithmetic functionality\n
|
* - integral constant based, operation and arithmetic functionality\n
|
||||||
* meta defines wrappers for all of integral types such as \c int, \c long, \c char, \c uint32_t etc...
|
* meta defines wrappers for all of integral types such as \c int, \c long, \c char, \c uint32_t etc...
|
||||||
* and also facilities to emulate:
|
* and also facilities to emulate:
|
||||||
* 1. <b>conditional (if)</b>
|
* 1. <b>conditional (if)</b>
|
||||||
* 2. <b>logical operations</b> like \c or, \c and, \c not, \c bitor, \c bitand etc...
|
* 2. <b>logical operations</b> like \c or, \c and, \c not, \c bitor, \c bitand etc...
|
||||||
* 3. <b>math operations</b> like \c add, \c sub, \c modulo
|
* 3. <b>math operations</b> like \c add, \c sub, \c modulo
|
||||||
* 4. <b>comparison operations</b> like \c equal, \c not_equal etc...
|
* 4. <b>comparison operations</b> like \c equal, \c not_equal etc...
|
||||||
|
*
|
||||||
* All of these operate on integral types.
|
* All of these operate on integral types.
|
||||||
|
*
|
||||||
* - <b>SFINAE</b> wrappers as syntactic sugar to the rest of the uTL.
|
* - <b>SFINAE</b> wrappers as syntactic sugar to the rest of the uTL.
|
||||||
|
*
|
||||||
* - Walter's Brown <b>detection idiom</b> to help uTL concept implementation.
|
* - Walter's Brown <b>detection idiom</b> to help uTL concept implementation.
|
||||||
|
*
|
||||||
* - <b>Higher order</b> metafunction tools for composition.\n
|
* - <b>Higher order</b> metafunction tools for composition.\n
|
||||||
* This module provides tools such as \c wrap, \c compose, \c fold, \c bind etc... The user can
|
* This module provides tools such as \c wrap, \c compose, \c fold, \c bind etc... The user can
|
||||||
* wrap metafunctions as types and pass them around other metafunctions. The evaluation
|
* wrap metafunctions as types and pass them around to other metafunctions. The evaluation
|
||||||
* of these functions can be done both aggressive or lazy using tools such as \c eval or \c invoke
|
* of these functions can be done both in aggressive or lazy maner using tools such as \c eval or \c invoke
|
||||||
|
*
|
||||||
* - <b>typelist "container"</b> implementation.\n
|
* - <b>typelist "container"</b> implementation.\n
|
||||||
* Typelist is a container like template type holding the parameter list as items in the container.
|
* Typelist is a container like template type holding the parameter list as items in the container.
|
||||||
* This facility has also all the expected eco-system of functions like \c push_front,
|
* This facility has also all the expected eco-system of functions like \c push_front,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#define __utl_meta_sfinae_h__
|
#define __utl_meta_sfinae_h__
|
||||||
|
|
||||||
#include <utl/core/impl.h>
|
#include <utl/core/impl.h>
|
||||||
|
#include <utl/meta/basic.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -53,12 +54,12 @@ namespace meta {
|
|||||||
//! If same type resolves to _Ret, else SFINAE
|
//! If same type resolves to _Ret, else SFINAE
|
||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename _T1, typename _T2, typename _Ret =_T1>
|
||||||
using use_if_same_t = enable_if_t<
|
using use_if_same_t = enable_if_t<
|
||||||
same_<_T1, _T2>::value, _Ret
|
same<_T1, _T2>::value, _Ret
|
||||||
>;
|
>;
|
||||||
//! If not same type resolves to _Ret, else SFINAE
|
//! If not same type resolves to _Ret, else SFINAE
|
||||||
template <typename _T1, typename _T2, typename _Ret =_T1>
|
template <typename _T1, typename _T2, typename _Ret =_T1>
|
||||||
using use_if_not_same_t = enable_if_t<
|
using use_if_not_same_t = enable_if_t<
|
||||||
!same_<_T1, _T2>::value, _Ret
|
!same<_T1, _T2>::value, _Ret
|
||||||
>;
|
>;
|
||||||
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
|
//! If any type (_T1 or _T2) type resolves to _Ret, else to SFINAE
|
||||||
template <typename T1, typename... Ts>
|
template <typename T1, typename... Ts>
|
||||||
|
|||||||
+55
-39
@@ -13,6 +13,30 @@
|
|||||||
/*!
|
/*!
|
||||||
* \ingroup meta
|
* \ingroup meta
|
||||||
* \defgroup typelist typelist
|
* \defgroup typelist typelist
|
||||||
|
*
|
||||||
|
* 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 an object, not a subject.
|
||||||
|
* This way the name gives the feeling of a container and smells like Python.\n
|
||||||
|
*
|
||||||
|
* 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).\n
|
||||||
|
*
|
||||||
|
* \code{.cpp}
|
||||||
|
* using l1 = typelist<int, void*, double, void>;
|
||||||
|
* l1 a {};
|
||||||
|
* \endcode
|
||||||
|
*
|
||||||
|
* boost::hana [3] suggests a more powerful scheme were type invariant structures can be used
|
||||||
|
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
|
||||||
|
* responsibility that comes along).\n
|
||||||
|
* 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/ \n
|
||||||
|
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html \n
|
||||||
|
* [3]: https://github.com/boostorg/hana \n
|
||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
|
|
||||||
@@ -21,31 +45,8 @@ namespace meta {
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief
|
* \brief
|
||||||
* A class template that just holds a parameter pack.
|
* The \c typelist 's implementation container
|
||||||
*
|
* \tparam Ts The \a contained types
|
||||||
* 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 an object, not a subject.
|
|
||||||
* This way the name gives the feeling of a container and smells like Python.\n
|
|
||||||
*
|
|
||||||
* 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).\n
|
|
||||||
*
|
|
||||||
* \code{.cpp}
|
|
||||||
* using l1 = typelist<int, void*, double, void>;
|
|
||||||
* l1 a {};
|
|
||||||
* \endcode
|
|
||||||
*
|
|
||||||
* boost::hana [3] suggests a more powerful scheme were type invariant structures can be used
|
|
||||||
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
|
|
||||||
* responsibility that comes along).\n
|
|
||||||
* 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/ \n
|
|
||||||
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html \n
|
|
||||||
* [3]: https://github.com/boostorg/hana \n
|
|
||||||
*/
|
*/
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct typelist {
|
struct typelist {
|
||||||
@@ -157,12 +158,12 @@ namespace meta {
|
|||||||
template <typename Fn, typename Seq>
|
template <typename Fn, typename Seq>
|
||||||
struct apply_ { };
|
struct apply_ { };
|
||||||
|
|
||||||
//! \c Sequence == typelist<>
|
// Sequence == typelist<>
|
||||||
template<typename Fn, typename ...List>
|
template<typename Fn, typename ...List>
|
||||||
struct apply_<Fn, typelist<List...>> {
|
struct apply_<Fn, typelist<List...>> {
|
||||||
using type = invoke<Fn, List...>;
|
using type = invoke<Fn, List...>;
|
||||||
};
|
};
|
||||||
//! Sequence == integer_sequence<>
|
// Sequence == integer_sequence<>
|
||||||
template <typename Fn, typename T, T... Is>
|
template <typename Fn, typename T, T... Is>
|
||||||
struct apply_<Fn, integer_sequence<T, Is...>> {
|
struct apply_<Fn, integer_sequence<T, Is...>> {
|
||||||
using type = invoke<Fn, integral_<T, Is>...>;
|
using type = invoke<Fn, integral_<T, Is>...>;
|
||||||
@@ -170,14 +171,13 @@ namespace meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Apply the Invocable \c Fn using the types in the type \c Seq as arguments.
|
* \brief
|
||||||
|
* Apply the Invocable \c Fn using the types in the type \c Seq as arguments.
|
||||||
* \note
|
* \note
|
||||||
* This is the opposed operation of typelist<Ts...>
|
* This is the opposed operation of typelist<Ts...>
|
||||||
*
|
*
|
||||||
* If \c Seq == typelist<> then
|
* If \c Seq == typelist<> then unpack typelist and apply to \c Fn \n
|
||||||
* Unpack typelist and apply to \c Fn
|
* It \c Seq == integer_sequence<> then unpack and use the integral_c<> of each integer
|
||||||
* It \c Seq == integer_sequence<> then
|
|
||||||
* Unpack and use the integral_c<> of each integer
|
|
||||||
*/
|
*/
|
||||||
template <typename Fn, typename Seq>
|
template <typename Fn, typename Seq>
|
||||||
using apply = apply_impl::apply_<Fn, Seq>;
|
using apply = apply_impl::apply_<Fn, Seq>;
|
||||||
@@ -244,7 +244,7 @@ namespace meta {
|
|||||||
//! @{
|
//! @{
|
||||||
namespace front_impl {
|
namespace front_impl {
|
||||||
template <typename L>
|
template <typename L>
|
||||||
struct front_ { };
|
struct front_ { using type = nil_; };
|
||||||
|
|
||||||
template <typename Head, typename... Tail>
|
template <typename Head, typename... Tail>
|
||||||
struct front_<typelist<Head, Tail...>> {
|
struct front_<typelist<Head, Tail...>> {
|
||||||
@@ -265,7 +265,7 @@ namespace meta {
|
|||||||
//! @{
|
//! @{
|
||||||
namespace back_impl {
|
namespace back_impl {
|
||||||
template <typename List>
|
template <typename List>
|
||||||
struct back_ { };
|
struct back_ { using type = nil_; };
|
||||||
|
|
||||||
template <typename Head, typename... Tail>
|
template <typename Head, typename... Tail>
|
||||||
struct back_<typelist<Head, Tail...>> {
|
struct back_<typelist<Head, Tail...>> {
|
||||||
@@ -636,7 +636,7 @@ namespace meta {
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Search for the first \c Item on the \c List for which the predicate \c Pred
|
* Search for the first \c Item on the \c List for which the predicate \c Pred
|
||||||
* returns true_ when `eval<invoke<Pred, Item>>`
|
* yields to \c true_ when `eval<invoke<Pred, Item>>`
|
||||||
*
|
*
|
||||||
* Complexity \f$ O(N) \f$
|
* Complexity \f$ O(N) \f$
|
||||||
*
|
*
|
||||||
@@ -684,7 +684,7 @@ namespace meta {
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Search for the first \c Item on the \c List for which the predicate \c Pred
|
* Search for the first \c Item on the \c List for which the predicate \c Pred
|
||||||
* returns true_ when `eval<invoke<Pred, Item>>` and return the rest of the \c List
|
* yields to \c true_ when `eval<invoke<Pred, Item>>` and return the rest of the \c List
|
||||||
* starting from that position as new typelist
|
* starting from that position as new typelist
|
||||||
*
|
*
|
||||||
* Complexity \f$ O(N) \f$
|
* Complexity \f$ O(N) \f$
|
||||||
@@ -705,6 +705,22 @@ namespace meta {
|
|||||||
using seek = seek_if <List, same_as<T>>;
|
using seek = seek_if <List, same_as<T>>;
|
||||||
//! @}
|
//! @}
|
||||||
|
|
||||||
|
//! \name first_if
|
||||||
|
//! @{
|
||||||
|
/*!
|
||||||
|
* Search and returns the first \c Item on the \c List for which the predicate \c Pred
|
||||||
|
* yields to true_ when \code eval<invoke<Pred, Item>> \endcode
|
||||||
|
*
|
||||||
|
* Complexity \f$ O(N) \f$
|
||||||
|
*
|
||||||
|
* \tparam List A typelist
|
||||||
|
* \tparam Pred A Unary invocable predicate
|
||||||
|
* \return On success the item, otherwise utl::meta::nil_
|
||||||
|
*/
|
||||||
|
template <typename List, typename Pred>
|
||||||
|
using first_if = front<seek_if<List, Pred>>;
|
||||||
|
//! @}
|
||||||
|
|
||||||
//! \name count_if
|
//! \name count_if
|
||||||
//! @{
|
//! @{
|
||||||
namespace count_if_impl {
|
namespace count_if_impl {
|
||||||
@@ -780,8 +796,8 @@ namespace meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Return a new typelist with elements, the elements of \c List that satisfy the
|
* Returns a new typelist with elements, the elements of \c List that satisfy the
|
||||||
* invocable \c Pred such that `eval<invoke<Pred, Item>>` is \c true_
|
* invocable \c Pred such that `eval<invoke<Pred, Item>>` yields to \c true_
|
||||||
*
|
*
|
||||||
* Complexity \f$ O(N) \f$
|
* Complexity \f$ O(N) \f$
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -12,13 +12,16 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
//! \defgroup utility Utility
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \ingroup utility
|
* \ingroup utility
|
||||||
* \defgroup invoke Invoke
|
* \defgroup util_invoke Invoke
|
||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
namespace utl {
|
namespace utl {
|
||||||
|
|
||||||
|
//#if !defined __cpp_lib_is_invocable
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@@ -101,16 +104,41 @@ namespace utl {
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
//! Invoke a callable object (for C++14)
|
//! Invoke the Callable object \c fn with the parameters args.
|
||||||
template<typename _Callable, typename... _Args>
|
//! As by INVOKE(std::forward<F>(f), std::forward<Args>(args)...).
|
||||||
inline decltype(auto) invoke(_Callable&& fn, _Args&&... args) {
|
//!
|
||||||
|
//! \note
|
||||||
|
//! This implementation fills the lack of an invoke() utility for builds
|
||||||
|
//! pre-c++17.
|
||||||
|
//!
|
||||||
|
//! \param fn Callable object to be invoked
|
||||||
|
//! \param args Arguments to pass to \c fn
|
||||||
|
//! \return The return of the Callable underling functionality
|
||||||
|
//!
|
||||||
|
template<typename Callable, typename... Args>
|
||||||
|
inline decltype(auto) invoke(Callable&& fn, Args&&... args) {
|
||||||
return detail::invoke_impl_(
|
return detail::invoke_impl_(
|
||||||
std::forward<_Callable>(fn), std::forward<_Args>(args)...
|
std::forward<Callable>(fn), std::forward<Args>(args)...
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
//! @}
|
|
||||||
|
|
||||||
//! std::is_invocable trait for C++14
|
//!
|
||||||
|
//! \brief
|
||||||
|
//! Determines whether \c F can be invoked with the arguments \c Args....
|
||||||
|
//!
|
||||||
|
//! Formally, determines whether invoke(declval<Fn>(), declval<ArgTypes>()...)
|
||||||
|
//! is well formed when treated as an unevaluated operand,
|
||||||
|
//! where invoke is \c Callable.
|
||||||
|
//!
|
||||||
|
//! \note
|
||||||
|
//! This implementation fills the lack of an invoke() utility for builds
|
||||||
|
//! pre-c++17.
|
||||||
|
//!
|
||||||
|
//! \tparam F The candidate type to check if its invocable
|
||||||
|
//! \tparam Args The arguments for the call
|
||||||
|
//! \return If \c F is invocable
|
||||||
|
//! \arg true Is invocable
|
||||||
|
//! \arg false Is not invocable
|
||||||
template <typename F, typename... Args>
|
template <typename F, typename... Args>
|
||||||
struct is_invocable :
|
struct is_invocable :
|
||||||
std::is_constructible<
|
std::is_constructible<
|
||||||
@@ -118,7 +146,19 @@ namespace utl {
|
|||||||
std::reference_wrapper<typename std::remove_reference<F>::type>
|
std::reference_wrapper<typename std::remove_reference<F>::type>
|
||||||
> { };
|
> { };
|
||||||
|
|
||||||
//! std::is_invocable_r trait for C++14
|
//! \brief
|
||||||
|
//! Determines whether \c F can be invoked with the arguments \c Args...
|
||||||
|
//! to yield a result that is convertible to \c R.
|
||||||
|
//!
|
||||||
|
//! Formally, determines whether invoke(declval<Fn>(), declval<ArgTypes>()...)
|
||||||
|
//! is well formed when treated as an unevaluated operand, where invoke is \c Callable.
|
||||||
|
//!
|
||||||
|
//! \tparam R The return type of invocable functionality
|
||||||
|
//! \tparam F The candidate type to check if its invocable
|
||||||
|
//! \tparam Args The arguments to pass to \c F
|
||||||
|
//! \return If \c F is invocable
|
||||||
|
//! \arg true Is invocable
|
||||||
|
//! \arg false Is not invocable
|
||||||
template <typename R, typename F, typename... Args>
|
template <typename R, typename F, typename... Args>
|
||||||
struct is_invocable_r :
|
struct is_invocable_r :
|
||||||
std::is_constructible<
|
std::is_constructible<
|
||||||
@@ -131,38 +171,55 @@ namespace utl {
|
|||||||
*/
|
*/
|
||||||
//! @{
|
//! @{
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename _Callable, typename... _Args>
|
template<typename Callable, typename... Args>
|
||||||
struct try_invoke {
|
struct try_invoke {
|
||||||
using type = decltype (
|
using type = decltype (
|
||||||
detail::invoke_impl_(std::declval<_Callable&&>(), std::declval<_Args&&>()...)
|
detail::invoke_impl_(std::declval<Callable&&>(), std::declval<Args&&>()...)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool B, typename _Callable, typename... _Args>
|
template<bool B, typename Callable, typename... Args>
|
||||||
struct invoke_result_ {
|
struct invoke_result_ {
|
||||||
using type = meta::nil_;
|
using type = meta::nil_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename _Callable, typename... _Args>
|
template <typename Callable, typename... Args>
|
||||||
struct invoke_result_ <true, _Callable, _Args...> {
|
struct invoke_result_ <true, Callable, Args...> {
|
||||||
using type = meta::invoke_t<
|
using type = meta::invoke_t<
|
||||||
meta::quote<try_invoke>, _Callable, _Args...
|
meta::quote<try_invoke>, Callable, Args...
|
||||||
>;
|
>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//! invoke_result (for C++14)
|
//! trait that deduces the return type of an INVOKE expression at compile time.
|
||||||
template <typename _Callable, typename... _Args>
|
//!
|
||||||
|
//! \tparam Callable The candidate type to check if its invocable
|
||||||
|
//! \tparam Args The arguments to pass to \c F
|
||||||
|
//!
|
||||||
|
//! \b member \n
|
||||||
|
//! \::type The return type of the \c Callable type if invoked with the arguments Args....
|
||||||
|
template <typename Callable, typename... Args>
|
||||||
using invoke_result = detail::invoke_result_<
|
using invoke_result = detail::invoke_result_<
|
||||||
is_invocable<_Callable, _Args...>::value,
|
is_invocable<Callable, Args...>::value,
|
||||||
_Callable,
|
Callable,
|
||||||
_Args...
|
Args...
|
||||||
>;
|
>;
|
||||||
|
|
||||||
//! invoke_result_t (for C++14)
|
//! trait that deduces the return type of an INVOKE expression at compile time.
|
||||||
template<typename _Callable, typename... _Args>
|
//!
|
||||||
|
//! \tparam Callable The candidate type to check if its invocable
|
||||||
|
//! \tparam Args The arguments to pass to \c F
|
||||||
|
//!
|
||||||
|
//! \return The type of the \c Callable type if invoked with the arguments Args....
|
||||||
|
template<typename Callable, typename... Args>
|
||||||
using invoke_result_t = meta::eval <
|
using invoke_result_t = meta::eval <
|
||||||
invoke_result<_Callable, _Args...>
|
invoke_result<Callable, Args...>
|
||||||
>;
|
>;
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//#else
|
||||||
|
//using is_invocable = std::is_invocable;
|
||||||
|
//
|
||||||
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//! @}
|
//! @}
|
||||||
|
|||||||
+104
-51
@@ -17,12 +17,55 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
# ========== Project settings ==========
|
# ult notes:
|
||||||
|
# ==============
|
||||||
|
# This makefile provides support for unix-like local builds and
|
||||||
|
# docker based builds for gcc and clang.
|
||||||
|
# ** msvc is not currently supported.
|
||||||
|
#
|
||||||
|
# Use cases:
|
||||||
|
# 1) build localy using **local rules** in terminal.
|
||||||
|
# example:
|
||||||
|
# make -j4 MK_ARG="-std=c++14 -fconcepts" build-gcc
|
||||||
|
#
|
||||||
|
# 2) build localy using **docker based rules** via terminal or script
|
||||||
|
# in order to compile for all compilers/versions/dialects.
|
||||||
|
# example in bash:
|
||||||
|
# #!/bin/bash
|
||||||
|
# for im in gcc:8 gcc:9 gcc:10; do
|
||||||
|
# for dial in -std=c++14 -std=c++17; do
|
||||||
|
# make IMAGE="$im" MK_ARG="$dial" dock-gcc
|
||||||
|
# done
|
||||||
|
# done
|
||||||
|
#
|
||||||
|
# 3) build inside a docker instance using **local rules** in order to
|
||||||
|
# build and test using a CD/CI system.
|
||||||
|
# example in a yml file:
|
||||||
|
# image: gcc:8
|
||||||
|
# build:
|
||||||
|
# stage: build
|
||||||
|
# - make MK_ARG="-std=c++14" build-gcc
|
||||||
|
# - make MK_ARG="-std=c++14 -fconcepts" build-gcc
|
||||||
|
# - make MK_ARG="-std=c++17" build-gcc
|
||||||
|
# - make MK_ARG="-std=c++17 -fconcepts" build-gcc
|
||||||
|
# - make MK_ARG="-std=c++2a" build-gcc
|
||||||
|
# ... etc
|
||||||
|
# test:
|
||||||
|
# stage: test
|
||||||
|
# - bin/utlTest
|
||||||
|
# ... etc
|
||||||
|
|
||||||
|
|
||||||
|
# ============== Project settings ==============
|
||||||
|
# Project's name
|
||||||
|
PROJECT := utl
|
||||||
# Excecutable's name
|
# Excecutable's name
|
||||||
TARGET := utlTest
|
TARGET := utlTest
|
||||||
# Source directories list(space seperated). Full or relative path
|
# Source directories list(space seperated).
|
||||||
|
# Relative path, under current directory only
|
||||||
SRC_DIR_LIST := tests gtest
|
SRC_DIR_LIST := tests gtest
|
||||||
# Include directories list(space seperated). Full or relative path
|
# Include directories list(space seperated).
|
||||||
|
# Relative path
|
||||||
INC_DIR_LIST := ../include gtest
|
INC_DIR_LIST := ../include gtest
|
||||||
# Exclude files list(space seperated). Filenames only.
|
# Exclude files list(space seperated). Filenames only.
|
||||||
# EXC_FILE_LIST := bad.cpp old.cpp
|
# EXC_FILE_LIST := bad.cpp old.cpp
|
||||||
@@ -32,7 +75,7 @@ BUILD_DIR := bin
|
|||||||
OBJ_DIR := $(BUILD_DIR)/obj
|
OBJ_DIR := $(BUILD_DIR)/obj
|
||||||
DEP_DIR := $(BUILD_DIR)/.dep
|
DEP_DIR := $(BUILD_DIR)/.dep
|
||||||
|
|
||||||
# ========== Compiler settings ==========
|
# ============== Compiler settings ==============
|
||||||
CLANGXX := clang++
|
CLANGXX := clang++
|
||||||
GCCXX := g++
|
GCCXX := g++
|
||||||
CSIZE := size
|
CSIZE := size
|
||||||
@@ -42,21 +85,35 @@ REL_CFLAGS := -Wall -Wextra -O2
|
|||||||
# Pre-defines
|
# Pre-defines
|
||||||
# PRE_DEFS := MYCAB=1729 SUPER_MODE
|
# PRE_DEFS := MYCAB=1729 SUPER_MODE
|
||||||
|
|
||||||
# ========== Linker settings ==========
|
# ============== Linker settings ==============
|
||||||
# Linker flags
|
# Linker flags
|
||||||
LDFLAGS := -pthread
|
LDFLAGS := -pthread
|
||||||
# Map output file
|
# Map output file
|
||||||
MAP_FILE := output.map
|
MAP_FILE := output.map
|
||||||
MAP_FLAG := -Xlinker -Map=$(BUILD_DIR)/$(MAP_FILE)
|
MAP_FLAG := -Xlinker -Map=$(BUILD_DIR)/$(MAP_FILE)
|
||||||
|
|
||||||
# ========== Default settings ==========
|
# ============== Docker settings ==============
|
||||||
# compiler and compiler flagfs
|
# We need:
|
||||||
|
# 1) Bind the entire project directory(the dir that icludes all the code) as volume.
|
||||||
|
# 2) In docker instance change to working directory(where the makefile is).
|
||||||
|
# For utl we use the directories `${PWD%/*}` and `test`.
|
||||||
|
# We double-$$ for double evaluating.
|
||||||
|
DOCKER_VOL_DIR := "$${PWD%/*}"
|
||||||
|
DOCKER_WRK_DIR := test
|
||||||
|
DOCKER_RUN := docker run --rm -v $(DOCKER_VOL_DIR):/usr/src/$(PROJECT) -w /usr/src/$(PROJECT)/$(DOCKER_WRK_DIR)
|
||||||
|
|
||||||
|
# ============== Default settings ==============
|
||||||
|
# compiler and compiler flags. By default docker is not used.
|
||||||
CFLAGS := $(DEB_CFLAGS)
|
CFLAGS := $(DEB_CFLAGS)
|
||||||
CXX := $(GCCXX)
|
CXX := $(GCCXX)
|
||||||
|
DOCKER :=
|
||||||
|
|
||||||
#
|
#
|
||||||
# =========== Main body and Patterns ===========
|
# =========== Main body and Patterns ===========
|
||||||
#
|
#
|
||||||
|
ifeq ($(OS), Windows_NT)
|
||||||
|
TARGET := $(TARGET).exe
|
||||||
|
endif
|
||||||
INC := $(foreach dir,$(INC_DIR_LIST),-I$(dir))
|
INC := $(foreach dir,$(INC_DIR_LIST),-I$(dir))
|
||||||
DEF := $(foreach def,$(PRE_DEFS),-D$(def))
|
DEF := $(foreach def,$(PRE_DEFS),-D$(def))
|
||||||
EXC := $(foreach fil,$(EXC_FILE_LIST), \
|
EXC := $(foreach fil,$(EXC_FILE_LIST), \
|
||||||
@@ -67,10 +124,11 @@ EXC := $(foreach fil,$(EXC_FILE_LIST), \
|
|||||||
SRC := $(wildcard *.cpp)
|
SRC := $(wildcard *.cpp)
|
||||||
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/*.cpp))
|
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/*.cpp))
|
||||||
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/**/*.cpp))
|
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/**/*.cpp))
|
||||||
SRC := $(abspath $(filter-out $(EXC),$(SRC)))
|
#SRC := $(abspath $(filter-out $(EXC),$(SRC)))
|
||||||
|
SRC := $(filter-out $(EXC),$(SRC))
|
||||||
|
|
||||||
OBJ := $(foreach file,$(SRC:%.cpp=%.o),$(OBJ_DIR)$(file))
|
OBJ := $(foreach file,$(SRC:%.cpp=%.o),$(OBJ_DIR)/$(file))
|
||||||
DEP := $(foreach file,$(SRC:%.cpp=%.d),$(DEP_DIR)$(file))
|
DEP := $(foreach file,$(SRC:%.cpp=%.d),$(DEP_DIR)/$(file))
|
||||||
|
|
||||||
|
|
||||||
# Make Dependencies pattern.
|
# Make Dependencies pattern.
|
||||||
@@ -80,14 +138,14 @@ DEP := $(foreach file,$(SRC:%.cpp=%.d),$(DEP_DIR)$(file))
|
|||||||
# It is based on Tom Tromey's method.
|
# It is based on Tom Tromey's method.
|
||||||
#
|
#
|
||||||
# Invoke cpp to create makefile rules with dependencies for each source file
|
# Invoke cpp to create makefile rules with dependencies for each source file
|
||||||
$(DEP_DIR)%.d: %.cpp
|
$(DEP_DIR)/%.d: %.cpp
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@$(CXX) -E $(CFLAGS) $(INC) $(DEF) -MM -MT $(OBJ_DIR)$(<:.cpp=.o) -MF $@ $<
|
@$(DOCKER) $(CXX) -E $(CFLAGS) $(INC) $(DEF) -MM -MT $(OBJ_DIR)/$(<:.cpp=.o) -MF $@ $<
|
||||||
|
|
||||||
# objects depent on .cpp AND dependency files, which have an empty recipe
|
# objects depent on .cpp AND dependency files, which have an empty recipe
|
||||||
$(OBJ_DIR)%.o: %.cpp $(DEP_DIR)%.d
|
$(OBJ_DIR)/%.o: %.cpp $(DEP_DIR)/%.d
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
$(CXX) -c $(CFLAGS) $(INC) $(DEF) -o $@ $<
|
$(DOCKER) $(CXX) -c $(CFLAGS) $(INC) $(DEF) -o $@ $<
|
||||||
|
|
||||||
# empty recipe for dependency files. This prevents make errors
|
# empty recipe for dependency files. This prevents make errors
|
||||||
$(DEP):
|
$(DEP):
|
||||||
@@ -100,8 +158,8 @@ include $(wildcard $(DEP))
|
|||||||
$(BUILD_DIR)/$(TARGET): $(OBJ)
|
$(BUILD_DIR)/$(TARGET): $(OBJ)
|
||||||
@mkdir -p $(@D)
|
@mkdir -p $(@D)
|
||||||
@echo Linking to target: $(TARGET)
|
@echo Linking to target: $(TARGET)
|
||||||
@echo $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) '$$(OBJ)'
|
@echo $(DOCKER) $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) '$$(OBJ)'
|
||||||
@$(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) $(OBJ)
|
@$(DOCKER) $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) $(OBJ)
|
||||||
@echo
|
@echo
|
||||||
@echo Print size information
|
@echo Print size information
|
||||||
@$(CSIZE) $(@D)/$(TARGET)
|
@$(CSIZE) $(@D)/$(TARGET)
|
||||||
@@ -116,43 +174,19 @@ clean:
|
|||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ============ User Rules =============
|
# ================ Local build rules =================
|
||||||
|
# examples:
|
||||||
|
# make MK_ARG="-std=c++14 -fconcepts" build-gcc
|
||||||
|
# make MK_ARG="-std=c++17" build-clang
|
||||||
#
|
#
|
||||||
|
.PHONY: build-gcc
|
||||||
|
build-gcc: CFLAGS += $(MK_ARG)
|
||||||
|
build-gcc: $(BUILD_DIR)/$(TARGET)
|
||||||
|
|
||||||
.PHONY: gcc14
|
.PHONY: build-clang
|
||||||
gcc14: CFLAGS += -std=c++14
|
build-clang: CXX := $(CLANGXX)
|
||||||
gcc14: $(BUILD_DIR)/$(TARGET)
|
build-clang: CFLAGS += $(MK_ARG)
|
||||||
|
build-clang: $(BUILD_DIR)/$(TARGET)
|
||||||
.PHONY: gcc14_conc
|
|
||||||
gcc14_conc: CFLAGS += -std=c++14 -fconcepts
|
|
||||||
gcc14_conc: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: gcc17
|
|
||||||
gcc17: CFLAGS += -std=c++17
|
|
||||||
gcc17: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: gcc17_conc
|
|
||||||
gcc17_conc: CFLAGS += -std=c++17 -fconcepts
|
|
||||||
gcc17_conc: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: gcc2a
|
|
||||||
gcc2a: CFLAGS += -std=c++2a
|
|
||||||
gcc2a: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: clang14
|
|
||||||
clang14: CXX := $(CLANGXX)
|
|
||||||
clang14: CFLAGS += -std=c++14
|
|
||||||
clang14: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: clang17
|
|
||||||
clang17: CXX := $(CLANGXX)
|
|
||||||
clang17: CFLAGS += -std=c++17
|
|
||||||
clang17: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: clang2a
|
|
||||||
clang2a: CXX := $(CLANGXX)
|
|
||||||
clang2a: CFLAGS += -std=c++2a
|
|
||||||
clang2a: $(BUILD_DIR)/$(TARGET)
|
|
||||||
|
|
||||||
.PHONY: debug
|
.PHONY: debug
|
||||||
debug: $(BUILD_DIR)/$(TARGET)
|
debug: $(BUILD_DIR)/$(TARGET)
|
||||||
@@ -163,3 +197,22 @@ release: clean $(BUILD_DIR)/$(TARGET)
|
|||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: clean release
|
all: clean release
|
||||||
|
|
||||||
|
#
|
||||||
|
# ================ Docker based rules ================
|
||||||
|
# examples:
|
||||||
|
# make IMAGE="gcc:8.3" MK_ARG="-std=c++14 -fconcepts" dock-gcc
|
||||||
|
# make IMAGE="a-clang-image" MK_ARG="-std=c++17" dock-clang
|
||||||
|
#
|
||||||
|
.PHONY: dock-gcc
|
||||||
|
dock-gcc: DOCKER := $(DOCKER_RUN) $(IMAGE)
|
||||||
|
dock-gcc: CFLAGS += $(MK_ARG)
|
||||||
|
dock-gcc: $(BUILD_DIR)/$(TARGET)
|
||||||
|
|
||||||
|
.PHONY: dock-clang
|
||||||
|
dock-clang: CXX := $(CLANGXX)
|
||||||
|
dock-clang: DOCKER := $(DOCKER_RUN) $(IMAGE)
|
||||||
|
dock-clang: CFLAGS += $(MK_ARG)
|
||||||
|
dock-clang: $(BUILD_DIR)/$(TARGET)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
-2
@@ -19,11 +19,14 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
GTEST_API_ int main(int argc, char **argv) {
|
GTEST_API_ int main(int argc, char **argv) try {
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e) {
|
||||||
|
std::cout << "Exception: " << e.what() << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -140,9 +140,9 @@ namespace TmetaBasic {
|
|||||||
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_, true_>>()));
|
EXPECT_EQ (true, (std::is_same<true_, and_<true_, true_, true_>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<false_, and_<true_, true_, false_>>()));
|
EXPECT_EQ (true, (std::is_same<false_, and_<true_, true_, false_>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (same_<Foo, Foo>()));
|
EXPECT_EQ (true, (same<Foo, Foo>()));
|
||||||
EXPECT_EQ (false, (same_<Foo, Bar>()));
|
EXPECT_EQ (false, (same<Foo, Bar>()));
|
||||||
EXPECT_EQ (true, (not_same_<Foo, Bar>()));
|
EXPECT_EQ (true, (not_same<Foo, Bar>()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,11 +218,11 @@ namespace TmetaBasic {
|
|||||||
/*
|
/*
|
||||||
* SFINAE
|
* SFINAE
|
||||||
*/
|
*/
|
||||||
template <typename T, typename =when<same_<T, int>::type::value>>
|
template <typename T, typename =when<same<T, int>::type::value>>
|
||||||
int check1 (T x) { return x; }
|
int check1 (T x) { return x; }
|
||||||
int check1 (...) { return 0; }
|
int check1 (...) { return 0; }
|
||||||
|
|
||||||
template <typename T, typename =enable_if_t<same_<T, int>::type::value, void>>
|
template <typename T, typename =enable_if_t<same<T, int>::type::value, void>>
|
||||||
int check2 (T x) { return x; }
|
int check2 (T x) { return x; }
|
||||||
int check2 (...) { return 0; }
|
int check2 (...) { return 0; }
|
||||||
|
|
||||||
|
|||||||
@@ -174,7 +174,9 @@ namespace TmetaTypelist {
|
|||||||
EXPECT_EQ (true, (std::is_same<long, at<l, int_<3>>>()));
|
EXPECT_EQ (true, (std::is_same<long, at<l, int_<3>>>()));
|
||||||
|
|
||||||
EXPECT_EQ (true, (std::is_same<char*, front<l>>()));
|
EXPECT_EQ (true, (std::is_same<char*, front<l>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<nil_, front<typelist<>>>()));
|
||||||
EXPECT_EQ (true, (std::is_same<short, back<l>>()));
|
EXPECT_EQ (true, (std::is_same<short, back<l>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<nil_, back<typelist<>>>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TmetaTypelist, Concat) {
|
TEST(TmetaTypelist, Concat) {
|
||||||
|
|||||||
Reference in New Issue
Block a user