meta: Compilation correction for previous 3 commits
This commit is contained in:
parent
899efcc2d6
commit
5f6eef3478
34
include/utl/concepts/concepts.h
Normal file
34
include/utl/concepts/concepts.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*!
|
||||||
|
* \file /utl/concepts/concepts.h
|
||||||
|
* \brief Concepts main include header
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_concepts_concepts_h__
|
||||||
|
#define __utl_consepts_concepts_h__
|
||||||
|
|
||||||
|
#include <utl/core/impl.h>
|
||||||
|
|
||||||
|
#include <utl/concepts/defines.h>
|
||||||
|
#include <utl/concepts/stl.h>
|
||||||
|
#include <utl/concepts/iterators.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \defgroup concepts
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* __utl_concepts_concepts_h__ */
|
69
include/utl/concepts/defines.h
Normal file
69
include/utl/concepts/defines.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*!
|
||||||
|
* \file /utl/concepts/defines.h
|
||||||
|
* \brief Concepts defines
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_concepts_defines_h__
|
||||||
|
#define __utl_concepts_defines_h__
|
||||||
|
|
||||||
|
//!\defgroup concepts
|
||||||
|
//!@{
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief
|
||||||
|
* utl typename constraints wrapper
|
||||||
|
*
|
||||||
|
* \example
|
||||||
|
* \code
|
||||||
|
* template <utlConstrainType(SomeConcept) T> struct lala { };
|
||||||
|
* // will expand to something like:
|
||||||
|
* // template <SomeConcept T> struct lala { };
|
||||||
|
* // or
|
||||||
|
* // template <typename T> struct lala { };
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
#define utlConstrainType(_Concept_) _Concept_
|
||||||
|
#else
|
||||||
|
#define utlConstrainType(_Concept_) typename
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \brief
|
||||||
|
* utl concept keyword syntax wrapper
|
||||||
|
*/
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
#if __cpp_concepts <= 201507L
|
||||||
|
#define _utlConcept concept bool
|
||||||
|
#else
|
||||||
|
#define _utlConcept concept
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define _utlConcept constexpr bool
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CXX_LIB_INVOKE
|
||||||
|
#ifdef __cpp_lib_invoke
|
||||||
|
#define CXX_LIB_INVOKE __cpp_lib_invoke
|
||||||
|
#else
|
||||||
|
#define CXX_LIB_INVOKE 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
#endif /* __utl_concepts_defines_h__ */
|
70
include/utl/concepts/iterators.h
Normal file
70
include/utl/concepts/iterators.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*!
|
||||||
|
* \file /utl/impl/concepts/iterators.h
|
||||||
|
* \brief utl iterator concept support header
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_concepts_iterator_h__
|
||||||
|
#define __utl_concepts_iterator_h__
|
||||||
|
|
||||||
|
#include <utl/core/impl.h>
|
||||||
|
#include <utl/concepts/defines.h>
|
||||||
|
#include <utl/concepts/stl.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \ingroup concepts
|
||||||
|
* \defgroup iterators
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
namespace utl {
|
||||||
|
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
template <class I>
|
||||||
|
_utlConcept WeaklyIncrementable =
|
||||||
|
Semiregular<I> &&
|
||||||
|
requires(I i) {
|
||||||
|
{ ++i } -> Same<I>&; // not required to be equality preserving
|
||||||
|
i++; // not required to be equality preserving
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
namespace detail {
|
||||||
|
template <typename I> using try_ppI = decltype (++(std::declval<I>()));
|
||||||
|
template <typename I> using try_Ipp = decltype (std::declval<I>()++);
|
||||||
|
}
|
||||||
|
template <class I>
|
||||||
|
_utlConcept WeaklyIncrementable =
|
||||||
|
Semiregular<I>
|
||||||
|
&& Same<_ref_t<I>, meta::detected_t<detail::try_ppI, _ref_t<I>>>
|
||||||
|
&& meta::is_detected<detail::try_Ipp, _ref_t<I>>::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
template <class I>
|
||||||
|
_utlConcept DeviceIterator =
|
||||||
|
requires(I i) {
|
||||||
|
{ *i } -> auto&&; // Requires: i is dereferenceable
|
||||||
|
} &&
|
||||||
|
WeaklyIncrementable<I>;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
#endif /* __utl_concepts_iterator_h__ */
|
751
include/utl/concepts/stl.h
Normal file
751
include/utl/concepts/stl.h
Normal file
@ -0,0 +1,751 @@
|
|||||||
|
/*!
|
||||||
|
* \file /utl/concepts/stl.h
|
||||||
|
* \brief STL's Concepts
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 - 2019 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef __utl_concepts_stl_h__
|
||||||
|
#define __utl_concepts_stl_h__
|
||||||
|
|
||||||
|
#include <utl/core/impl.h>
|
||||||
|
#include <utl/meta/meta.h>
|
||||||
|
#include <utl/utility/invoke.h>
|
||||||
|
|
||||||
|
#include <utl/concepts/defines.h>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief
|
||||||
|
* STL's core language concepts
|
||||||
|
*
|
||||||
|
* We provide std concepts in case host's stl does not provide them yet.
|
||||||
|
*
|
||||||
|
* For more information \see https://en.cppreference.com/w/cpp/concepts
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
namespace utl {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using remove_cvref_t = std::remove_cv_t< std::remove_reference_t<T> >;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using cref_ = const std::remove_reference_t<T>&;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using _ref_t = std::add_lvalue_reference_t<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Same
|
||||||
|
*/
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept Same = meta::same_<T, U>::value;
|
||||||
|
|
||||||
|
// template<class T>
|
||||||
|
// _utlConcept Decayed = Same<T, std::decay_t<T>>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* DerivedFrom
|
||||||
|
*/
|
||||||
|
template <class Derived, class Base>
|
||||||
|
_utlConcept DerivedFrom =
|
||||||
|
std::is_base_of<Base, Derived>::value &&
|
||||||
|
std::is_convertible<const volatile Derived*, const volatile Base*>::value;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* ConvertibleTo
|
||||||
|
*/
|
||||||
|
template <class From, class To>
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
_utlConcept ConvertibleTo =
|
||||||
|
std::is_convertible<From, To>::value &&
|
||||||
|
requires(From (&f)()) {
|
||||||
|
static_cast<To>(f());
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
_utlConcept ConvertibleTo = std::is_convertible<From, To>::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Common Reference
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
namespace common_impl {
|
||||||
|
//! \see https://ericniebler.github.io/std/wg21/D0022.html
|
||||||
|
// ========== common reference ===========
|
||||||
|
template<class T, class U>
|
||||||
|
using __cond_res =
|
||||||
|
decltype(false ? std::declval<T(&)()>()() : std::declval<U(&)()>()());
|
||||||
|
|
||||||
|
template<class From>
|
||||||
|
struct __copy_cv_ {
|
||||||
|
static_assert(!std::is_reference<From>::value);
|
||||||
|
template<class To> using apply = To;
|
||||||
|
};
|
||||||
|
template<class From>
|
||||||
|
struct __copy_cv_<const From> {
|
||||||
|
template<class To> using apply = const To;
|
||||||
|
};
|
||||||
|
template<class From>
|
||||||
|
struct __copy_cv_<volatile From> {
|
||||||
|
template<class To> using apply = volatile To;
|
||||||
|
};
|
||||||
|
template<class From>
|
||||||
|
struct __copy_cv_<const volatile From> {
|
||||||
|
template<class To> using apply = const volatile To;
|
||||||
|
};
|
||||||
|
template<class From, class To>
|
||||||
|
using __copy_cv = meta::invoke<__copy_cv_<From>, To>;
|
||||||
|
|
||||||
|
// CREF [meta.trans.other]/2.1
|
||||||
|
template<class T>
|
||||||
|
using __cref = std::add_lvalue_reference_t<const std::remove_reference_t<T>>;
|
||||||
|
|
||||||
|
// COMMON_REF [meta.trans.other]/2
|
||||||
|
template<class T, class U, class = void>
|
||||||
|
struct __common_ref_ {
|
||||||
|
static_assert(std::is_reference<T>::value, "");
|
||||||
|
static_assert(std::is_reference<U>::value, "");
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
using __common_ref = meta::eval<__common_ref_<T, U>>;
|
||||||
|
|
||||||
|
// [meta.trans.other]/2.5
|
||||||
|
template<class T, class U>
|
||||||
|
using __lref_res = __cond_res<
|
||||||
|
__copy_cv<T, U> &,
|
||||||
|
__copy_cv<U, T> &
|
||||||
|
>;
|
||||||
|
|
||||||
|
// [meta.trans.other]/2.6
|
||||||
|
template<class T, class U, class R = __common_ref<T&, U&>>
|
||||||
|
using __rref_res = std::remove_reference_t<R>&&;
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
struct __common_ref_<T&, U&,
|
||||||
|
meta::void_t<__lref_res<T, U>,
|
||||||
|
meta::when<std::is_reference<__lref_res<T, U>>::value>> > {
|
||||||
|
using type = __lref_res<T, U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
struct __common_ref_<T&&, U&&,
|
||||||
|
meta::void_t<__common_ref<T&, U&>,
|
||||||
|
meta::when<ConvertibleTo<T&&, __rref_res<T, U>>>,
|
||||||
|
meta::when<ConvertibleTo<U&&, __rref_res<T, U>>>> > {
|
||||||
|
using type = __rref_res<T, U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// [meta.trans.other]/2.7
|
||||||
|
template<class T, class U>
|
||||||
|
struct __common_ref_<T&&, U&,
|
||||||
|
meta::void_t<__common_ref<const T&, U&>,
|
||||||
|
meta::when<ConvertibleTo<T&&, __common_ref<const T&, U&>>>> > {
|
||||||
|
using type = __common_ref<const T&, U&>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// [meta.trans.other]/2.8
|
||||||
|
template<class T, class U>
|
||||||
|
struct __common_ref_<T&, U&&,
|
||||||
|
meta::void_t<__common_ref<T&, const U&>,
|
||||||
|
meta::when<ConvertibleTo<U&&, __common_ref<T&, const U&>>>> > {
|
||||||
|
using type = __common_ref<T&, const U&>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class>
|
||||||
|
struct __xref {
|
||||||
|
template<class U> using apply = U;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct __xref<const T> {
|
||||||
|
template<class U> using apply = const U;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct __xref<volatile T> {
|
||||||
|
template<class U> using apply = volatile U;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct __xref<const volatile T> {
|
||||||
|
template<class U> using apply = const volatile U;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct __xref<T&> {
|
||||||
|
template<class U> using apply =
|
||||||
|
std::add_lvalue_reference_t<meta::invoke<__xref<T>, U>>;
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
struct __xref<T&&> {
|
||||||
|
template<class U> using apply =
|
||||||
|
std::add_rvalue_reference_t<meta::invoke<__xref<T>, U>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class,
|
||||||
|
class,
|
||||||
|
template<class> class,
|
||||||
|
template<class> class
|
||||||
|
>
|
||||||
|
struct basic_common_reference { };
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
using __basic_common_reference_t = meta::eval<
|
||||||
|
basic_common_reference<
|
||||||
|
remove_cvref_t<T>,
|
||||||
|
remove_cvref_t<U>,
|
||||||
|
__xref<T>::template apply,
|
||||||
|
__xref<U>::template apply
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
|
||||||
|
template<class...>
|
||||||
|
struct common_reference {};
|
||||||
|
|
||||||
|
template<class... Ts>
|
||||||
|
using common_reference_t = meta::eval<
|
||||||
|
common_reference<Ts...>
|
||||||
|
>;
|
||||||
|
|
||||||
|
// [meta.trans.other]/5.2
|
||||||
|
template<class T>
|
||||||
|
struct common_reference<T> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
// [meta.trans.other]/5.3.4
|
||||||
|
template<class T, class U, class...>
|
||||||
|
struct __common_reference3
|
||||||
|
: std::common_type<T, U> {};
|
||||||
|
|
||||||
|
// [meta.trans.other]/5.3.3
|
||||||
|
template<class T, class U>
|
||||||
|
struct __common_reference3<T, U,
|
||||||
|
meta::void_t<__cond_res<T, U>>> {
|
||||||
|
using type = __cond_res<T, U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U, class...>
|
||||||
|
struct __common_reference2
|
||||||
|
: __common_reference3<T, U> {};
|
||||||
|
|
||||||
|
// [meta.trans.other]/5.3.2
|
||||||
|
template<class T, class U>
|
||||||
|
struct __common_reference2<T, U,
|
||||||
|
meta::void_t<__basic_common_reference_t<T, U>>> {
|
||||||
|
using type = __basic_common_reference_t<T, U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, class U, class...>
|
||||||
|
struct __common_reference
|
||||||
|
: __common_reference2<T, U> { };
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
struct __common_reference<T, U,
|
||||||
|
meta::when<std::is_reference<T>::value && std::is_reference<U>::value>> {
|
||||||
|
using type = __common_ref<T, U>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T, class U>
|
||||||
|
struct common_reference<T, U> : __common_reference<T, U> { };
|
||||||
|
|
||||||
|
// [meta.trans.other]/5.4
|
||||||
|
template<class T, class U, class V, class... W>
|
||||||
|
//requires requires { typename common_reference_t<T, U>; }
|
||||||
|
struct common_reference<T, U, V, W...>
|
||||||
|
: common_reference <
|
||||||
|
common_reference_t<T, U>, V, W...
|
||||||
|
> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...Ts>
|
||||||
|
using common_reference = common_impl::common_reference<Ts...>;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
using common_reference_t = meta::eval<
|
||||||
|
common_reference<Ts...>
|
||||||
|
>;
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
|
||||||
|
//FIXME: CommonReference needs better implementation
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept CommonReference =
|
||||||
|
Same<common_reference_t<T, U>, common_reference_t<U, T>> &&
|
||||||
|
ConvertibleTo<T, common_reference_t<T, U>> &&
|
||||||
|
ConvertibleTo<U, common_reference_t<T, U>>;
|
||||||
|
|
||||||
|
|
||||||
|
// != std::Common on CommonReference
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept Common =
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
Same<std::common_type_t<T, U>, std::common_type_t<U, T>> &&
|
||||||
|
requires {
|
||||||
|
static_cast<std::common_type_t<T, U>>(std::declval<T>());
|
||||||
|
static_cast<std::common_type_t<T, U>>(std::declval<U>());
|
||||||
|
};
|
||||||
|
// } &&
|
||||||
|
// CommonReference<
|
||||||
|
// std::add_lvalue_reference_t<const T>,
|
||||||
|
// std::add_lvalue_reference_t<const U>> &&
|
||||||
|
// CommonReference<
|
||||||
|
// std::add_lvalue_reference_t<std::common_type_t<T, U>>,
|
||||||
|
// std::common_reference_t<
|
||||||
|
// std::add_lvalue_reference_t<const T>,
|
||||||
|
// std::add_lvalue_reference_t<const U>
|
||||||
|
// >
|
||||||
|
// >;
|
||||||
|
#else
|
||||||
|
// meta::and_ <
|
||||||
|
Same<std::common_type_t<T, U>, std::common_type_t<U, T>>; //>
|
||||||
|
// meta::bool_<CommonReference<
|
||||||
|
// std::add_lvalue_reference_t<const T>,
|
||||||
|
// std::add_lvalue_reference_t<const U>
|
||||||
|
// >>,
|
||||||
|
// meta::bool_< CommonReference<
|
||||||
|
// std::add_lvalue_reference_t<std::common_type_t<T, U>>,
|
||||||
|
// common_reference_t<
|
||||||
|
// std::add_lvalue_reference_t<const T>,
|
||||||
|
// std::add_lvalue_reference_t<const U>
|
||||||
|
// >
|
||||||
|
// >>
|
||||||
|
// >::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Integral
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept Integral = std::is_integral<T>::value;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Signed Integral
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept SignedIntegral = Integral<T> && std::is_signed<T>::value;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Unsigned Integral
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept UnsignedIntegral = Integral<T> && !std::is_signed<T>::value;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
_utlConcept MoveAssignable = std::is_move_assignable<T>::value;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
_utlConcept CopyAssignable = std::is_copy_assignable<T>::value;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Assignable
|
||||||
|
* \note != std:: on CommonReference
|
||||||
|
*/
|
||||||
|
template<class LHS, class RHS>
|
||||||
|
_utlConcept Assignable =
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
std::is_lvalue_reference<LHS>::value &&
|
||||||
|
// CommonReference<
|
||||||
|
// const std::remove_reference_t<L>&,
|
||||||
|
// const std::remove_reference_t<R>&> &&
|
||||||
|
requires(LHS lhs, RHS&& rhs) {
|
||||||
|
lhs = std::forward<RHS>(rhs);
|
||||||
|
requires Same<
|
||||||
|
decltype(lhs = std::forward<RHS>(rhs)), LHS
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
std::is_assignable<LHS, RHS>::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Swappable, SwappableWith
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
#if CXX_VER < CXX_VER_STD_17
|
||||||
|
namespace swappable_with_impl {
|
||||||
|
struct is_swappable_with_ {
|
||||||
|
// can apply std::swap
|
||||||
|
template<typename _Tp,
|
||||||
|
typename _Up,
|
||||||
|
typename
|
||||||
|
= decltype(std::swap(std::declval<_Tp&>(), std::declval<_Up&>())),
|
||||||
|
typename
|
||||||
|
= decltype(std::swap(std::declval<_Up&>(), std::declval<_Tp&>()))>
|
||||||
|
static meta::true_ check(int);
|
||||||
|
// can not apply std::swap
|
||||||
|
template<typename, typename> static meta::false_ check(...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
template <typename _Tp, typename _Up>
|
||||||
|
struct is_swappable_with
|
||||||
|
: swappable_with_impl::is_swappable_with_ {
|
||||||
|
using type = decltype(check<_Tp, _Up>(0));
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
using is_swappable = std::is_swappable;
|
||||||
|
using is_swappable_with = std::is_swappable_with;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// != std:: on CommonReference
|
||||||
|
template<class T, class U>
|
||||||
|
_utlConcept SwappableWith =
|
||||||
|
is_swappable_with<T, T>::type::value &&
|
||||||
|
is_swappable_with<U, U>::type::value &&
|
||||||
|
is_swappable_with<T, U>::type::value &&
|
||||||
|
is_swappable_with<U, T>::type::value;
|
||||||
|
// std::CommonReference<
|
||||||
|
// const std::remove_reference_t<T>&,
|
||||||
|
// const std::remove_reference_t<U>&
|
||||||
|
// >;
|
||||||
|
|
||||||
|
// != std:: we use is_swappable_with now is_swappable
|
||||||
|
template<class T>
|
||||||
|
_utlConcept Swappable = is_swappable_with<T, T>::type::value;
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Destructible
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept Destructible = std::is_nothrow_destructible<T>::value;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Constructible
|
||||||
|
*/
|
||||||
|
template <class T, class... Args>
|
||||||
|
_utlConcept Constructible =
|
||||||
|
Destructible<T> && std::is_constructible<T, Args...>::value;
|
||||||
|
/*!
|
||||||
|
* DefaultConstructible
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept DefaultConstructible = Constructible<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* MoveConstructible
|
||||||
|
* \note
|
||||||
|
* Another approach would be std::is_move_constructible<T>::value;
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
_utlConcept MoveConstructible =
|
||||||
|
Constructible<T, T> && ConvertibleTo<T, T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* CopyConstructible
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept CopyConstructible =
|
||||||
|
MoveConstructible<T> &&
|
||||||
|
Constructible<T, _ref_t<T>> && ConvertibleTo<_ref_t<T>, T> &&
|
||||||
|
Constructible<T, const _ref_t<T>> && ConvertibleTo<const _ref_t<T>, T> &&
|
||||||
|
Constructible<T, const T> && ConvertibleTo<const T, T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Movable
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept Movable =
|
||||||
|
std::is_object<T>::value &&
|
||||||
|
MoveConstructible<T> &&
|
||||||
|
Assignable<_ref_t<T>, T> &&
|
||||||
|
Swappable<T>;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Copyable
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept Copyable =
|
||||||
|
CopyConstructible<T> &&
|
||||||
|
Movable<T> &&
|
||||||
|
Assignable<_ref_t<T>, const _ref_t<T>>;
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Boolean
|
||||||
|
*/
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
template <class B>
|
||||||
|
_utlConcept Boolean =
|
||||||
|
Movable<remove_cvref_t<B>> &&
|
||||||
|
requires(const std::remove_reference_t<B>& b1,
|
||||||
|
const std::remove_reference_t<B>& b2, const bool a) {
|
||||||
|
requires ConvertibleTo<const std::remove_reference_t<B>&, bool>;
|
||||||
|
!b1; requires ConvertibleTo<decltype(!b1), bool>;
|
||||||
|
b1 && a; requires Same<decltype(b1 && a), bool>;
|
||||||
|
b1 || a; requires Same<decltype(b1 || a), bool>;
|
||||||
|
b1 && b2; requires Same<decltype(b1 && b2), bool>;
|
||||||
|
a && b2; requires Same<decltype(a && b2), bool>;
|
||||||
|
b1 || b2; requires Same<decltype(b1 || b2), bool>;
|
||||||
|
a || b2; requires Same<decltype(a || b2), bool>;
|
||||||
|
b1 == b2; requires ConvertibleTo<decltype(b1 == b2), bool>;
|
||||||
|
b1 == a; requires ConvertibleTo<decltype(b1 == a), bool>;
|
||||||
|
a == b2; requires ConvertibleTo<decltype(a == b2), bool>;
|
||||||
|
b1 != b2; requires ConvertibleTo<decltype(b1 != b2), bool>;
|
||||||
|
b1 != a; requires ConvertibleTo<decltype(b1 != a), bool>;
|
||||||
|
a != b2; requires ConvertibleTo<decltype(a != b2), bool>;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
namespace details {
|
||||||
|
template <typename B, typename = void>
|
||||||
|
struct is_boolean_ {
|
||||||
|
using type = meta::false_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename B>
|
||||||
|
struct is_boolean_ <B, meta::void_t<
|
||||||
|
meta::use_if_same_t<bool, decltype(!std::declval<cref_<B>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() == std::declval<cref_<B>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() != std::declval<cref_<B>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() && std::declval<cref_<B>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<B>>() || std::declval<cref_<B>>())>
|
||||||
|
>> {
|
||||||
|
using type = meta::true_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename B>
|
||||||
|
using is_boolean_t = meta::eval <
|
||||||
|
is_boolean_<B>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
template <class B>
|
||||||
|
_utlConcept Boolean =
|
||||||
|
Movable<remove_cvref_t<B>> &&
|
||||||
|
//ConvertibleTo<const std::remove_reference_t<B>&, bool> &&
|
||||||
|
ConvertibleTo<const _ref_t<B>, bool> &&
|
||||||
|
Same<meta::true_, details::is_boolean_t<B>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
template <typename T, typename U, typename = void>
|
||||||
|
struct is_weakly_equality_comparable_with_ {
|
||||||
|
using type = meta::false_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct is_weakly_equality_comparable_with_<T, U, meta::void_t<
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() == std::declval<cref_<U>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() != std::declval<cref_<U>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() == std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() != std::declval<cref_<T>>())>
|
||||||
|
>> {
|
||||||
|
using type = meta::true_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
using is_weakly_equality_comparable_with_t = meta::eval<
|
||||||
|
is_weakly_equality_comparable_with_ <T, U>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept WeaklyEqualityComparableWith =
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
requires(const std::remove_reference_t<T>& t,
|
||||||
|
const std::remove_reference_t<U>& u) {
|
||||||
|
t == u; requires Boolean<decltype(t == u)>;
|
||||||
|
t != u; requires Boolean<decltype(t != u)>;
|
||||||
|
u == t; requires Boolean<decltype(u == t)>;
|
||||||
|
u != t; requires Boolean<decltype(u != t)>;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
Same<meta::true_, details::is_weakly_equality_comparable_with_t<T, U>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
_utlConcept EqualityComparable = WeaklyEqualityComparableWith<T, T>;
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept EqualityComparableWith =
|
||||||
|
EqualityComparable<T> &&
|
||||||
|
EqualityComparable<U> &&
|
||||||
|
// CommonReference<
|
||||||
|
// const std::remove_reference_t<T>&,
|
||||||
|
// const std::remove_reference_t<U>&> &&
|
||||||
|
// EqualityComparable<
|
||||||
|
// common_reference_t<
|
||||||
|
// const std::remove_reference_t<T>&,
|
||||||
|
// const std::remove_reference_t<U>&>> &&
|
||||||
|
WeaklyEqualityComparableWith<T, U>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
template <class T>
|
||||||
|
_utlConcept StrictTotallyOrdered =
|
||||||
|
EqualityComparable<T> &&
|
||||||
|
requires(const std::remove_reference_t<T>& a,
|
||||||
|
const std::remove_reference_t<T>& b) {
|
||||||
|
a < b; requires Boolean<decltype(a < b)>;
|
||||||
|
a > b; requires Boolean<decltype(a > b)>;
|
||||||
|
a <= b; requires Boolean<decltype(a <= b)>;
|
||||||
|
a >= b; requires Boolean<decltype(a >= b)>;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
namespace details {
|
||||||
|
template <typename T, typename = void>
|
||||||
|
struct is_strict_totally_ordered_ {
|
||||||
|
using type = meta::false_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_strict_totally_ordered_ <T, meta::void_t <
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<T>>())>
|
||||||
|
>> {
|
||||||
|
using type = meta::true_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using is_strict_totally_ordered_t = meta::eval <
|
||||||
|
is_strict_totally_ordered_<T>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
template <class T>
|
||||||
|
_utlConcept StrictTotallyOrdered =
|
||||||
|
EqualityComparable<T> &&
|
||||||
|
Same <meta::true_, details::is_strict_totally_ordered_t<T>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CXX_CONCEPTS
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept StrictTotallyOrderedWith =
|
||||||
|
StrictTotallyOrdered<T> &&
|
||||||
|
StrictTotallyOrdered<U> &&
|
||||||
|
// CommonReference<
|
||||||
|
// const std::remove_reference_t<T>&,
|
||||||
|
// const std::remove_reference_t<U>&
|
||||||
|
// > &&
|
||||||
|
// StrictTotallyOrdered<
|
||||||
|
// common_reference_t<
|
||||||
|
// const std::remove_reference_t<T>&,
|
||||||
|
// const std::remove_reference_t<U>&
|
||||||
|
// >
|
||||||
|
// > &&
|
||||||
|
EqualityComparableWith<T, U> &&
|
||||||
|
requires(const std::remove_reference_t<T>& t,
|
||||||
|
const std::remove_reference_t<U>& u) {
|
||||||
|
t < u; requires Boolean<decltype(t < u)>;
|
||||||
|
t > u; requires Boolean<decltype(t > u)>;
|
||||||
|
t <= u; requires Boolean<decltype(t <= u)>;
|
||||||
|
t >= u; requires Boolean<decltype(t >= u)>;
|
||||||
|
u < t; requires Boolean<decltype(u < t)>;
|
||||||
|
u > t; requires Boolean<decltype(u > t)>;
|
||||||
|
u <= t; requires Boolean<decltype(u <= t)>;
|
||||||
|
u >= t; requires Boolean<decltype(u >= t)>;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
namespace details {
|
||||||
|
template <typename T, typename U, typename = void>
|
||||||
|
struct is_strict_totally_ordered_with_ {
|
||||||
|
using type = meta::false_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
struct is_strict_totally_ordered_with_ <T, U, meta::void_t <
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() < std::declval<cref_<U>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() > std::declval<cref_<U>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() <= std::declval<cref_<U>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<T>>() >= std::declval<cref_<U>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() < std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() > std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() <= std::declval<cref_<T>>())>,
|
||||||
|
meta::use_if_same_t<bool, decltype(std::declval<cref_<U>>() >= std::declval<cref_<T>>())>
|
||||||
|
>> {
|
||||||
|
using type = meta::true_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename U>
|
||||||
|
using is_strict_totally_ordered_with_t = meta::eval <
|
||||||
|
is_strict_totally_ordered_with_<T, U>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
template <class T, class U>
|
||||||
|
_utlConcept StrictTotallyOrderedWith =
|
||||||
|
StrictTotallyOrdered<T> &&
|
||||||
|
StrictTotallyOrdered<U> &&
|
||||||
|
EqualityComparableWith<T, U> &&
|
||||||
|
Same <meta::true_, details::is_strict_totally_ordered_with_t<T, U>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Semiregular
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept Semiregular = Copyable<T> && DefaultConstructible<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Regular
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
_utlConcept Regular = Semiregular<T> && EqualityComparable<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Scalar
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
_utlConcept Scalar =
|
||||||
|
std::is_scalar<T>::value && Regular<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Arithmetic
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
_utlConcept Arithmetic =
|
||||||
|
std::is_arithmetic<T>::value && Scalar<T> && StrictTotallyOrdered<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* FloatingPoint
|
||||||
|
*/
|
||||||
|
template<class T>
|
||||||
|
_utlConcept FloatingPoint =
|
||||||
|
std::is_floating_point<T>::value && Arithmetic<T>;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Invocable
|
||||||
|
*/
|
||||||
|
template <class F, class... Args>
|
||||||
|
_utlConcept Invocable = is_invocable<F, Args...>::value;
|
||||||
|
// requires(F&& f, Args&&... args) {
|
||||||
|
// invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||||
|
// };
|
||||||
|
|
||||||
|
template< class F, class... Args >
|
||||||
|
_utlConcept RegularInvocable = Invocable<F, Args...>;
|
||||||
|
|
||||||
|
template < class F, class... Args >
|
||||||
|
_utlConcept Predicate =
|
||||||
|
RegularInvocable<F, Args...> &&
|
||||||
|
Boolean<invoke_result_t<F, Args...>>;
|
||||||
|
|
||||||
|
template <class R, class T, class U>
|
||||||
|
_utlConcept Relation =
|
||||||
|
Predicate<R, T, T> && Predicate<R, U, U> &&
|
||||||
|
Predicate<R, T, U> && Predicate<R, U, T>;
|
||||||
|
|
||||||
|
template < class R, class T, class U >
|
||||||
|
_utlConcept StrictWeakOrder = Relation<R, T, U>;
|
||||||
|
}
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __utl_concepts_stl_h__ */
|
187
include/utl/utility/invoke.h
Normal file
187
include/utl/utility/invoke.h
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
/*!
|
||||||
|
* \file utl/utility/invoke.h
|
||||||
|
* \brief invoke() and invoke() traits implementation
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more detail.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef __utl_utility_invoke_h__
|
||||||
|
#define __utl_utility_invoke_h__
|
||||||
|
|
||||||
|
#include <utl/core/impl.h>
|
||||||
|
#include <utl/meta/meta.h>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \ingroup utility
|
||||||
|
* \defgroup invoke
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
namespace utl {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct is_ref_wrapper : meta::false_ {};
|
||||||
|
template <class U>
|
||||||
|
struct is_ref_wrapper<std::reference_wrapper<U>> : meta::true_ {};
|
||||||
|
|
||||||
|
// 1
|
||||||
|
template <class T, class Type, class T1, class... Args,
|
||||||
|
meta::enable_if_t<
|
||||||
|
std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
|
||||||
|
std::is_base_of<T, std::decay_t<T1>>::value,
|
||||||
|
int> =0
|
||||||
|
>
|
||||||
|
decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
|
||||||
|
return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2
|
||||||
|
template <class T, class Type, class T1, class... Args,
|
||||||
|
meta::enable_if_t<
|
||||||
|
std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
|
||||||
|
is_ref_wrapper<std::decay_t<T1>>::value,
|
||||||
|
int> =0
|
||||||
|
>
|
||||||
|
decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
|
||||||
|
return (t1.get().*f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3
|
||||||
|
template <class T, class Type, class T1, class... Args,
|
||||||
|
meta::enable_if_t<
|
||||||
|
std::is_member_function_pointer<std::decay_t<Type T::*>>::value &&
|
||||||
|
!std::is_base_of<T, std::decay_t<T1>>::value &&
|
||||||
|
!is_ref_wrapper<std::decay_t<T1>>::value,
|
||||||
|
int> =0
|
||||||
|
>
|
||||||
|
decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
|
||||||
|
return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4
|
||||||
|
template <class T, class Type, class T1, class... Args,
|
||||||
|
meta::enable_if_t<
|
||||||
|
std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
|
||||||
|
std::is_base_of<T, std::decay_t<T1>>::value,
|
||||||
|
int> =0
|
||||||
|
>
|
||||||
|
decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
|
||||||
|
return std::forward<T1>(t1).*f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5
|
||||||
|
template <class T, class Type, class T1, class... Args,
|
||||||
|
meta::enable_if_t<
|
||||||
|
std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
|
||||||
|
is_ref_wrapper<std::decay_t<T1>>::value,
|
||||||
|
int> =0
|
||||||
|
>
|
||||||
|
decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
|
||||||
|
return t1.get().*f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6
|
||||||
|
template <class T, class Type, class T1, class... Args,
|
||||||
|
meta::enable_if_t<
|
||||||
|
std::is_member_object_pointer<std::decay_t<Type T::*>>::value &&
|
||||||
|
!std::is_base_of<T, std::decay_t<T1>>::value &&
|
||||||
|
!is_ref_wrapper<std::decay_t<T1>>::value,
|
||||||
|
int> =0
|
||||||
|
>
|
||||||
|
decltype(auto) invoke_impl_(Type T::* f, T1&& t1, Args&&... args) {
|
||||||
|
return (*std::forward<T1>(t1)).*f;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F, class... Args>
|
||||||
|
decltype(auto) invoke_impl_(F&& f, Args&&... args) {
|
||||||
|
return std::forward<F>(f)(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
//! Invoke a callable object (for C++14)
|
||||||
|
template<typename _Callable, typename... _Args>
|
||||||
|
inline decltype(auto) invoke(_Callable&& fn, _Args&&... args) {
|
||||||
|
return detail::invoke_impl_(
|
||||||
|
std::forward<_Callable>(fn), std::forward<_Args>(args)...
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
//! std::is_invocable trait for C++11
|
||||||
|
template <typename F, typename... Args>
|
||||||
|
struct is_invocable :
|
||||||
|
std::is_constructible<
|
||||||
|
std::function<void(Args ...)>,
|
||||||
|
std::reference_wrapper<typename std::remove_reference<F>::type>
|
||||||
|
> { };
|
||||||
|
|
||||||
|
//! std::is_invocable_r trait for C++11
|
||||||
|
template <typename R, typename F, typename... Args>
|
||||||
|
struct is_invocable_r :
|
||||||
|
std::is_constructible<
|
||||||
|
std::function<R(Args ...)>,
|
||||||
|
std::reference_wrapper<typename std::remove_reference<F>::type>
|
||||||
|
> { };
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* invoke_result (SFINAE friendly)
|
||||||
|
*/
|
||||||
|
//! @{
|
||||||
|
namespace detail {
|
||||||
|
template<typename _Callable, typename... _Args>
|
||||||
|
struct try_invoke {
|
||||||
|
using type = decltype (
|
||||||
|
detail::invoke_impl_(std::declval<_Callable&&>(), std::declval<_Args&&>()...)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool B, typename _Callable, typename... _Args>
|
||||||
|
struct invoke_result_ {
|
||||||
|
using type = meta::nil_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Callable, typename... _Args>
|
||||||
|
struct invoke_result_ <true, _Callable, _Args...> {
|
||||||
|
using type = meta::invoke_t<
|
||||||
|
meta::quote<try_invoke>, _Callable, _Args...
|
||||||
|
>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//! invoke_result (for C++14)
|
||||||
|
template <typename _Callable, typename... _Args>
|
||||||
|
using invoke_result = detail::invoke_result_<
|
||||||
|
is_invocable<_Callable, _Args...>::value,
|
||||||
|
_Callable,
|
||||||
|
_Args...
|
||||||
|
>;
|
||||||
|
|
||||||
|
//! invoke_result_t (for C++14)
|
||||||
|
template<typename _Callable, typename... _Args>
|
||||||
|
using invoke_result_t = meta::eval <
|
||||||
|
invoke_result<_Callable, _Args...>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! @}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __utl_utility_invoke_h__ */
|
422
test/tests/TConcepts.cpp
Normal file
422
test/tests/TConcepts.cpp
Normal file
@ -0,0 +1,422 @@
|
|||||||
|
/*!
|
||||||
|
* \file Tmeta.cpp
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <utl/concepts/concepts.h>
|
||||||
|
#include <utl/meta/meta.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace test_concepts {
|
||||||
|
using namespace utl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fixture like types
|
||||||
|
*/
|
||||||
|
struct Empty { };
|
||||||
|
struct HaveOnlyCopy {
|
||||||
|
HaveOnlyCopy(const HaveOnlyCopy&) = default;
|
||||||
|
HaveOnlyCopy(HaveOnlyCopy&&) = delete;
|
||||||
|
HaveOnlyCopy& operator= (const HaveOnlyCopy&) = default;
|
||||||
|
HaveOnlyCopy& operator= (HaveOnlyCopy&&) = delete;
|
||||||
|
};
|
||||||
|
struct HaveOnlyMove {
|
||||||
|
HaveOnlyMove(const HaveOnlyMove&) = delete;
|
||||||
|
HaveOnlyMove(HaveOnlyMove&&) = default;
|
||||||
|
HaveOnlyMove& operator= (const HaveOnlyMove&) = delete;
|
||||||
|
HaveOnlyMove& operator= (HaveOnlyMove&&) = default;
|
||||||
|
};
|
||||||
|
struct HaveCopyAndMove {
|
||||||
|
HaveCopyAndMove(const HaveCopyAndMove&) = default;
|
||||||
|
HaveCopyAndMove(HaveCopyAndMove&&) = default;
|
||||||
|
HaveCopyAndMove& operator= (const HaveCopyAndMove&) = default;
|
||||||
|
HaveCopyAndMove& operator= (HaveCopyAndMove&&) = default;
|
||||||
|
};
|
||||||
|
class HavePerfectForwarding {
|
||||||
|
public: template<class T> HavePerfectForwarding(T&&) { }
|
||||||
|
};
|
||||||
|
class Base { };
|
||||||
|
class Derived1 : public Base { };
|
||||||
|
class Derived2 : public Derived1 { };
|
||||||
|
class HaveOperatorBase {
|
||||||
|
public: operator Base() { return base; }
|
||||||
|
Base base;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
int a_;
|
||||||
|
public:
|
||||||
|
A(int a =0) : a_{a} { };
|
||||||
|
A(const A&) = default;
|
||||||
|
A(A&&) = default;
|
||||||
|
};
|
||||||
|
bool operator== (const A& l, const A& r) { return l.a_ == r.a_; }
|
||||||
|
bool operator!= (const A& l, const A& r) { return l.a_ != r.a_; }
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
int b_;
|
||||||
|
public:
|
||||||
|
B(int b =0) : b_{b} { };
|
||||||
|
B(const B&) = default;
|
||||||
|
B(B&&) = default;
|
||||||
|
B& operator= (const B&) = default;
|
||||||
|
B& operator= (B&&) = default;
|
||||||
|
};
|
||||||
|
bool operator== (const B& l, const B& r) { return l.b_ == r.b_; }
|
||||||
|
bool operator!= (const B& l, const B& r) { return l.b_ != r.b_; }
|
||||||
|
bool operator< (const B& l, const B& r) { return l.b_ < r.b_; }
|
||||||
|
bool operator<= (const B& l, const B& r) { return l.b_ <= r.b_; }
|
||||||
|
bool operator> (const B& l, const B& r) { return l.b_ > r.b_; }
|
||||||
|
bool operator>= (const B& l, const B& r) { return l.b_ >= r.b_; }
|
||||||
|
|
||||||
|
|
||||||
|
TEST(TConcepts, Same) {
|
||||||
|
// Same
|
||||||
|
EXPECT_EQ (true, (Same<int, int>));
|
||||||
|
EXPECT_EQ (false, (Same<int, long>));
|
||||||
|
EXPECT_EQ (true, (Same<int*, int*>));
|
||||||
|
EXPECT_EQ (true, (Same<double&, double&>));
|
||||||
|
EXPECT_EQ (false, (Same<int, Empty>));
|
||||||
|
EXPECT_EQ (false, (Same<Base, Derived1>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, DerivedFrom) {
|
||||||
|
// DerivedFrom
|
||||||
|
EXPECT_EQ (true, (DerivedFrom<Derived1, Base>));
|
||||||
|
EXPECT_EQ (true, (DerivedFrom<Derived2, Derived1>));
|
||||||
|
EXPECT_EQ (true, (DerivedFrom<Derived2, Base>));
|
||||||
|
EXPECT_EQ (false, (DerivedFrom<Base, Derived1>));
|
||||||
|
EXPECT_EQ (false, (DerivedFrom<Base, int>));
|
||||||
|
EXPECT_EQ (false, (DerivedFrom<void, int>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, ConvertibleTo) {
|
||||||
|
// ConvertibleTo
|
||||||
|
EXPECT_EQ (true, (ConvertibleTo<void, void>));
|
||||||
|
EXPECT_EQ (false, (ConvertibleTo<Base, void>));
|
||||||
|
EXPECT_EQ (false, (ConvertibleTo<Base*, Derived1*>));
|
||||||
|
EXPECT_EQ (true, (ConvertibleTo<Derived1*, Base*>));
|
||||||
|
EXPECT_EQ (true, (ConvertibleTo<HaveOperatorBase, Base>));
|
||||||
|
EXPECT_EQ (true, (ConvertibleTo<Base, HavePerfectForwarding>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, CommonReference) {
|
||||||
|
// CommonReference
|
||||||
|
EXPECT_EQ (true, (CommonReference<Derived1, Base>));
|
||||||
|
EXPECT_EQ (true, (CommonReference<Derived1&, Base>));
|
||||||
|
EXPECT_EQ (true, (CommonReference<const Empty&&, const Empty&>));
|
||||||
|
EXPECT_EQ (false, (CommonReference<Empty&, const volatile Empty&>));
|
||||||
|
//FIXME: CommonReference needs SFINAE friendly implementation
|
||||||
|
//EXPECT_EQ (false, (CommonReference<Empty&&, const volatile Empty&>)); <- yields compiler error
|
||||||
|
|
||||||
|
// Common
|
||||||
|
EXPECT_EQ (true, (Common<int, int>));
|
||||||
|
EXPECT_EQ (true, (Common<Base, Derived1>));
|
||||||
|
EXPECT_EQ (true, (Common<Derived1, Derived2>));
|
||||||
|
EXPECT_EQ (true, (Common<Base, HaveOperatorBase>));
|
||||||
|
EXPECT_EQ (true, (Common<Base, HavePerfectForwarding>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Integral) {
|
||||||
|
// Integral
|
||||||
|
EXPECT_EQ (false, (Integral<void>));
|
||||||
|
EXPECT_EQ (true, (Integral<int>));
|
||||||
|
EXPECT_EQ (true, (Integral<bool>));
|
||||||
|
EXPECT_EQ (false, (Integral<int*>));
|
||||||
|
EXPECT_EQ (false, (Integral<Base>));
|
||||||
|
EXPECT_EQ (true, (Integral<meta::int_<42>::value_type>));
|
||||||
|
EXPECT_EQ (false, (Integral<meta::int_<42>::type>));
|
||||||
|
|
||||||
|
// SignedIntegral
|
||||||
|
EXPECT_EQ (false, (SignedIntegral<void>));
|
||||||
|
EXPECT_EQ (true, (SignedIntegral<int>));
|
||||||
|
EXPECT_EQ (false, (SignedIntegral<int*>));
|
||||||
|
EXPECT_EQ (false, (SignedIntegral<unsigned long>));
|
||||||
|
EXPECT_EQ (false, (SignedIntegral<double>));
|
||||||
|
EXPECT_EQ (false, (SignedIntegral<Base>));
|
||||||
|
EXPECT_EQ (true, (SignedIntegral<meta::int16_<42>::value_type>));
|
||||||
|
|
||||||
|
// UnsignedIntegral
|
||||||
|
EXPECT_EQ (false, (UnsignedIntegral<void>));
|
||||||
|
EXPECT_EQ (true, (UnsignedIntegral<unsigned int>));
|
||||||
|
EXPECT_EQ (false, (UnsignedIntegral<long>));
|
||||||
|
EXPECT_EQ (false, (UnsignedIntegral<double>));
|
||||||
|
EXPECT_EQ (false, (UnsignedIntegral<Base>));
|
||||||
|
EXPECT_EQ (true, (UnsignedIntegral<meta::uint16_<42>::value_type>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Assignable) {
|
||||||
|
// MoveAssignable
|
||||||
|
EXPECT_EQ (false, (MoveAssignable<void>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<void*>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<int>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<int*>));
|
||||||
|
EXPECT_EQ (false, (MoveAssignable<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<Empty>));
|
||||||
|
EXPECT_EQ (true, (MoveAssignable<HavePerfectForwarding>));
|
||||||
|
|
||||||
|
// CopyAssignable
|
||||||
|
EXPECT_EQ (false, (CopyAssignable<void>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<void*>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<int>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<int*>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (false, (CopyAssignable<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<Empty>));
|
||||||
|
EXPECT_EQ (true, (CopyAssignable<HavePerfectForwarding>));
|
||||||
|
|
||||||
|
// Assignable
|
||||||
|
EXPECT_EQ (false, (Assignable<void, void>));
|
||||||
|
EXPECT_EQ (false, (Assignable<int&, void>));
|
||||||
|
EXPECT_EQ (true, (Assignable<int&, int>));
|
||||||
|
EXPECT_EQ (false, (Assignable<int, int>));
|
||||||
|
EXPECT_EQ (false, (Assignable<int*, int*>));
|
||||||
|
EXPECT_EQ (true, (Assignable<Base&, Derived1>));
|
||||||
|
EXPECT_EQ (false, (Assignable<Derived1&, Base>));
|
||||||
|
EXPECT_EQ (true, (Assignable<HaveOnlyMove&, HaveOnlyMove&&>));
|
||||||
|
EXPECT_EQ (true , (Assignable<HaveOnlyMove&, HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (true, (Assignable<Empty&, Empty>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Swappable) {
|
||||||
|
// Swappable, SwappableWith
|
||||||
|
EXPECT_EQ (false, (Swappable<void>));
|
||||||
|
EXPECT_EQ (true, (Swappable<void*>));
|
||||||
|
EXPECT_EQ (true, (Swappable<int>));
|
||||||
|
EXPECT_EQ (true, (Swappable<Base>));
|
||||||
|
EXPECT_EQ (true, (SwappableWith<int, int>));
|
||||||
|
EXPECT_EQ (false, (SwappableWith<int, Base>));
|
||||||
|
EXPECT_EQ (false, (SwappableWith<Base, Derived1>));
|
||||||
|
|
||||||
|
// Destructible
|
||||||
|
EXPECT_EQ (false, (Destructible<void>));
|
||||||
|
EXPECT_EQ (true, (Destructible<void*>));
|
||||||
|
EXPECT_EQ (true, (Destructible<int>));
|
||||||
|
EXPECT_EQ (true, (Destructible<int&>));
|
||||||
|
EXPECT_EQ (true, (Destructible<Base>));
|
||||||
|
EXPECT_EQ (true, (Destructible<HavePerfectForwarding>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Constructible) {
|
||||||
|
// Constructible
|
||||||
|
EXPECT_EQ (false, (Constructible<void>));
|
||||||
|
EXPECT_EQ (true, (Constructible<void*>));
|
||||||
|
EXPECT_EQ (true, (Constructible<Base>));
|
||||||
|
EXPECT_EQ (false, (Constructible<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (true, (Constructible<HavePerfectForwarding, int>));
|
||||||
|
|
||||||
|
// DefaultConstructible
|
||||||
|
EXPECT_EQ (false, (DefaultConstructible<void>));
|
||||||
|
EXPECT_EQ (true, (DefaultConstructible<void*>));
|
||||||
|
EXPECT_EQ (false, (DefaultConstructible<int&>));
|
||||||
|
EXPECT_EQ (true, (DefaultConstructible<Base>));
|
||||||
|
EXPECT_EQ (true, (DefaultConstructible<Derived1>));
|
||||||
|
EXPECT_EQ (false, (DefaultConstructible<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (false, (DefaultConstructible<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (DefaultConstructible<HavePerfectForwarding>));
|
||||||
|
|
||||||
|
// MoveConstructible
|
||||||
|
EXPECT_EQ (false, (MoveConstructible<void>));
|
||||||
|
EXPECT_EQ (true, (MoveConstructible<void*>));
|
||||||
|
EXPECT_EQ (true, (MoveConstructible<Base>));
|
||||||
|
EXPECT_EQ (true, (MoveConstructible<Derived1>));
|
||||||
|
EXPECT_EQ (true, (MoveConstructible<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (MoveConstructible<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (true, (MoveConstructible<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (true , (MoveConstructible<HavePerfectForwarding>));
|
||||||
|
|
||||||
|
// CopyConstructible
|
||||||
|
EXPECT_EQ (false, (CopyConstructible<void>));
|
||||||
|
EXPECT_EQ (true, (CopyConstructible<void*>));
|
||||||
|
EXPECT_EQ (true, (CopyConstructible<Base>));
|
||||||
|
EXPECT_EQ (true, (CopyConstructible<Derived1>));
|
||||||
|
EXPECT_EQ (false, (CopyConstructible<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (CopyConstructible<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (true, (CopyConstructible<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (true , (CopyConstructible<HavePerfectForwarding>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, MovableCopyable) {
|
||||||
|
// Movable
|
||||||
|
EXPECT_EQ (false, (Movable<void>));
|
||||||
|
EXPECT_EQ (true, (Movable<int>));
|
||||||
|
EXPECT_EQ (true, (Movable<Base>));
|
||||||
|
EXPECT_EQ (true, (Movable<Derived1>));
|
||||||
|
EXPECT_EQ (true, (Movable<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (Movable<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (true, (Movable<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (true , (Movable<HavePerfectForwarding>));
|
||||||
|
|
||||||
|
// Copyable
|
||||||
|
EXPECT_EQ (false, (Copyable<void>));
|
||||||
|
EXPECT_EQ (true, (Copyable<int>));
|
||||||
|
EXPECT_EQ (true, (Copyable<Base>));
|
||||||
|
EXPECT_EQ (true, (Copyable<Derived1>));
|
||||||
|
EXPECT_EQ (false, (Copyable<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (Copyable<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (true, (Copyable<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (true , (Copyable<HavePerfectForwarding>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Boolean) {
|
||||||
|
// Boolean
|
||||||
|
EXPECT_EQ (false, (Boolean<void>));
|
||||||
|
EXPECT_EQ (true, (Boolean<bool>));
|
||||||
|
EXPECT_EQ (true, (Boolean<int>));
|
||||||
|
EXPECT_EQ (true, (Boolean<double>));
|
||||||
|
EXPECT_EQ (true, (Boolean<std::true_type>));
|
||||||
|
EXPECT_EQ (true, (Boolean<meta::true_>));
|
||||||
|
EXPECT_EQ (false, (Boolean<Empty>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Comparable) {
|
||||||
|
// EqualityComparable
|
||||||
|
EXPECT_EQ (false, (EqualityComparable<void>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparable<bool>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparable<int>));
|
||||||
|
EXPECT_EQ (false, (EqualityComparable<Empty>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparable<A>));
|
||||||
|
|
||||||
|
// EqualityComparableWith
|
||||||
|
EXPECT_EQ (false, (EqualityComparableWith<void, bool>));
|
||||||
|
EXPECT_EQ (false, (EqualityComparableWith<void, void>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparableWith<bool, bool>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparableWith<int, int>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparableWith<int, bool>));
|
||||||
|
EXPECT_EQ (false, (EqualityComparableWith<Empty, Empty>));
|
||||||
|
EXPECT_EQ (false, (EqualityComparableWith<int, Empty>));
|
||||||
|
EXPECT_EQ (true, (EqualityComparableWith<A, A>));
|
||||||
|
EXPECT_EQ (false, (EqualityComparableWith<A, B>));
|
||||||
|
|
||||||
|
// StrictTotallyOrdered
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrdered<void>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrdered<bool>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrdered<int>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrdered<double>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrdered<Empty>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrdered<A>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrdered<B>));
|
||||||
|
|
||||||
|
// StrictTotallyOrderedWith
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrderedWith<void, void>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrderedWith<int, void>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrderedWith<bool, bool>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrderedWith<int, double>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrderedWith<int, Empty>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrderedWith<Base, Derived1>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrderedWith<A, A>));
|
||||||
|
EXPECT_EQ (true, (StrictTotallyOrderedWith<B, B>));
|
||||||
|
EXPECT_EQ (false, (StrictTotallyOrderedWith<A, B>));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TConcepts, Types) {
|
||||||
|
// Semiregular
|
||||||
|
EXPECT_EQ (false, (Semiregular<void>));
|
||||||
|
EXPECT_EQ (true, (Semiregular<int>));
|
||||||
|
EXPECT_EQ (true, (Semiregular<Empty>));
|
||||||
|
EXPECT_EQ (false, (Semiregular<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (Semiregular<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (false, (Semiregular<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (false, (Semiregular<A>));
|
||||||
|
EXPECT_EQ (true, (Semiregular<B>));
|
||||||
|
|
||||||
|
// Regular
|
||||||
|
EXPECT_EQ (false, (Regular<void>));
|
||||||
|
EXPECT_EQ (true, (Regular<int>));
|
||||||
|
EXPECT_EQ (true, (Regular<int*>));
|
||||||
|
EXPECT_EQ (false, (Regular<Empty>));
|
||||||
|
EXPECT_EQ (false, (Regular<HaveOnlyMove>));
|
||||||
|
EXPECT_EQ (false, (Regular<HaveOnlyCopy>));
|
||||||
|
EXPECT_EQ (false, (Regular<HaveCopyAndMove>));
|
||||||
|
EXPECT_EQ (false, (Regular<A>));
|
||||||
|
EXPECT_EQ (true, (Regular<B>));
|
||||||
|
|
||||||
|
// Scalar
|
||||||
|
EXPECT_EQ (false, (Scalar<void>));
|
||||||
|
EXPECT_EQ (true, (Scalar<int>));
|
||||||
|
EXPECT_EQ (true, (Scalar<long*>));
|
||||||
|
EXPECT_EQ (false, (Scalar<A>));
|
||||||
|
EXPECT_EQ (false, (Scalar<B>));
|
||||||
|
|
||||||
|
// Arithmetic
|
||||||
|
EXPECT_EQ (false, (Arithmetic<void>));
|
||||||
|
EXPECT_EQ (true, (Arithmetic<int>));
|
||||||
|
EXPECT_EQ (false, (Arithmetic<long*>));
|
||||||
|
EXPECT_EQ (false, (Arithmetic<A>));
|
||||||
|
EXPECT_EQ (false, (Arithmetic<B>));
|
||||||
|
|
||||||
|
// FloatingPoint
|
||||||
|
EXPECT_EQ (false, (FloatingPoint<void>));
|
||||||
|
EXPECT_EQ (true, (FloatingPoint<float>));
|
||||||
|
EXPECT_EQ (true, (FloatingPoint<double>));
|
||||||
|
EXPECT_EQ (false, (FloatingPoint<int>));
|
||||||
|
EXPECT_EQ (false, (FloatingPoint<float*>));
|
||||||
|
EXPECT_EQ (false, (FloatingPoint<A>));
|
||||||
|
EXPECT_EQ (false, (FloatingPoint<B>));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Inv {
|
||||||
|
void operator() (int) { };
|
||||||
|
void operator() () { };
|
||||||
|
};
|
||||||
|
struct Pred {
|
||||||
|
bool operator () (int) { return true; }
|
||||||
|
bool operator () (int, int) { return true; }
|
||||||
|
};
|
||||||
|
TEST(TConcepts, Callable) {
|
||||||
|
EXPECT_EQ (true, (Invocable<Inv, int>));
|
||||||
|
EXPECT_EQ (true, (Invocable<Inv>));
|
||||||
|
EXPECT_EQ (true, (Invocable<Inv, double>));
|
||||||
|
EXPECT_EQ (false, (Invocable<Inv, Empty>));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (RegularInvocable<Inv, int>));
|
||||||
|
|
||||||
|
EXPECT_EQ (false, (Predicate<Inv, int>));
|
||||||
|
EXPECT_EQ (true, (Predicate<Pred, int>));
|
||||||
|
EXPECT_EQ (false, (Predicate<Pred, Empty>));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (Relation<Pred, int, int>));
|
||||||
|
EXPECT_EQ (true, (Relation<Pred, int, double>));
|
||||||
|
EXPECT_EQ (false, (Relation<Pred, Empty, int>));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (StrictWeakOrder<Pred, int, int>));
|
||||||
|
EXPECT_EQ (false, (StrictWeakOrder<Pred, int, Empty>));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Incr {
|
||||||
|
Incr& operator++() { return *this; }
|
||||||
|
Incr operator++(int) { return *this; }
|
||||||
|
};
|
||||||
|
int type_printer (int* i) { return *i; }
|
||||||
|
TEST(TConcepts, Iterators) {
|
||||||
|
|
||||||
|
// type_printer(detail::try_ppI<Incr&>{});
|
||||||
|
// type_printer(detail::try_Ipp<Incr&>{});
|
||||||
|
// type_printer(meta::detected_t<detail::try_ppI, int>{});
|
||||||
|
EXPECT_EQ (true, (WeaklyIncrementable<int>));
|
||||||
|
EXPECT_EQ (false, (WeaklyIncrementable<void>));
|
||||||
|
EXPECT_EQ (false, (WeaklyIncrementable<meta::nil_>));
|
||||||
|
EXPECT_EQ (true, (WeaklyIncrementable<Incr>));
|
||||||
|
EXPECT_EQ (false, (WeaklyIncrementable<Incr&>));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
72
test/tests/Tinvoke.cpp
Normal file
72
test/tests/Tinvoke.cpp
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*!
|
||||||
|
* \file Tinvoke.cpp
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2019 Christos Choutouridis
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <utl/utility/invoke.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace test_meta {
|
||||||
|
using namespace utl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types to behave like Fixtures
|
||||||
|
*/
|
||||||
|
int Ifun(int i) { return i; }
|
||||||
|
struct Ifoo {
|
||||||
|
int operator() (int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ibar {
|
||||||
|
Ibar(int num) : num_(num) {}
|
||||||
|
int echo(int i) const { return i; }
|
||||||
|
int get() const { return num_; }
|
||||||
|
int num_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test invoke()
|
||||||
|
*/
|
||||||
|
TEST(Tinvoke, Invoke) {
|
||||||
|
Ifoo ifoo{};
|
||||||
|
const Ibar ibar{42};
|
||||||
|
|
||||||
|
EXPECT_EQ (42, invoke(Ifun, 42));
|
||||||
|
EXPECT_EQ (42, invoke([] () { return Ifun(42); }));
|
||||||
|
EXPECT_EQ (42, invoke(Ifoo{}, 42));
|
||||||
|
EXPECT_EQ (42, invoke(ifoo, 42));
|
||||||
|
EXPECT_EQ (42, invoke(&Ibar::echo, ibar, 42));
|
||||||
|
EXPECT_EQ (42, invoke(&Ibar::get, ibar));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (is_invocable<Ifoo, int>::value));
|
||||||
|
EXPECT_EQ (false, (is_invocable<Ifoo>::value));
|
||||||
|
EXPECT_EQ (false, (is_invocable<Ifoo, int, double>::value));
|
||||||
|
EXPECT_EQ (false, (is_invocable<Ibar, int>::value));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (is_invocable_r<int, Ifoo, int>::value));
|
||||||
|
EXPECT_EQ (false, (is_invocable_r<int*, Ifoo, int>::value));
|
||||||
|
EXPECT_EQ (false, (is_invocable_r<int, Ifoo>::value));
|
||||||
|
|
||||||
|
EXPECT_EQ (true, (std::is_same<int, invoke_result_t<Ifoo, int>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<meta::nil_, invoke_result_t<Ifoo>>()));
|
||||||
|
EXPECT_EQ (true, (std::is_same<meta::nil_, invoke_result_t<Ifoo, int, double>>()));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user