6 Commits
Author SHA1 Message Date
hoo2 19d1fc6890 WIP: invoke c++17 rework 2021-10-04 21:13:30 +03:00
hoo2 a436935d89 WIP: concepts rework 2020-10-08 21:51:23 +03:00
Christos Choutouridis fa431d5be7 DEV: small twists 2020-10-08 16:02:00 +03:00
hoo2 d1242f969c DEV: new documentation setup 2020-10-07 22:09:20 +03:00
Christos Choutouridis ef5eb2c891 DEV: makefile support for windows based compilers 2020-10-06 11:49:09 +03:00
hoo2 d076b4ae38 DEV: Makefile changes (add docker support) 2020-09-28 20:33:23 +03:00
17 changed files with 527 additions and 301 deletions
+9 -5
View File
@@ -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
+1 -1
View File
@@ -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>
+2 -2
View File
@@ -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>>;
+6 -4
View File
@@ -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); }
} }
//!@} //!@}
+1 -1
View File
@@ -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)
+3 -3
View File
@@ -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;
+4 -4
View File
@@ -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>>>;
//! @} //! @}
//! @} //! @}
+5 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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,
+3 -2
View File
@@ -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
View File
@@ -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$
* *
+79 -22
View File
@@ -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
View File
@@ -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
View File
@@ -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';
}
+5 -5
View File
@@ -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; }
+2
View File
@@ -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) {