Improve implementation of traits for functions

This commit is contained in:
John Wellbelove 2025-12-08 09:11:17 +00:00
parent 57c50fce89
commit 31b658ba81
6 changed files with 915 additions and 108 deletions

View File

@ -21,7 +21,7 @@ copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
FITNESS FOR TArgs PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
@ -36,101 +36,251 @@ SOFTWARE.
#include "type_traits.h"
#if ETL_USING_CPP11
namespace etl
{
//***************************************************************************
/// A template to extract the function type traits.
// Primary template (unspecialized)
//***************************************************************************
template <typename T>
template <typename T, typename Enable = void>
struct function_traits;
//***************************************************************************
/// Specialisation for function pointers
// Base for plain function type TReturn(TArgs...)
//***************************************************************************
template <typename TReturn, typename... TArgs>
struct function_traits<TReturn(*)(TArgs...)>
struct function_traits<TReturn(TArgs...), void>
{
using function_type = TReturn(TArgs...); ///< The signature of the function.
using return_type = TReturn; ///< The return type.
using object_type = void; ///< The object type, if a member function.
using argument_types = etl::type_list<TArgs...>; ///< An etl::type_list containing the function argument types.
public:
static constexpr bool is_function = true; ///< <b>true</b> if the type is a free, static or global function, otherwise <b>false</b>.
static constexpr bool is_member_function = false; ///< <b>true</b> if the type is a member function, otherwise <b>false</b>.
static constexpr bool is_const = false; ///< <b>true</b> if the type is a const member function, otherwise <b>false</b>.
static constexpr size_t argument_count = sizeof...(TArgs); ///< The number of arguments that the function takes.
using function_type = TReturn(TArgs...);
using return_type = TReturn;
using object_type = void;
using argument_types = etl::type_list<TArgs...>;
static constexpr bool is_function = true;
static constexpr bool is_member_function = false;
static constexpr bool is_functor = false;
static constexpr bool is_const = false;
static constexpr bool is_volatile = false;
static constexpr bool is_noexcept = false;
static constexpr size_t arity = sizeof...(TArgs);
ETL_DEPRECATED_REASON("Use etl::function_traits::arity instead")
static constexpr size_t argument_count = arity;
};
//***************************************************************************
// Free function pointer
//***************************************************************************
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(*)(TArgs...)>::is_function;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(*)(TArgs...)>::is_member_function;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(*)(TArgs...)>::is_const;
template <typename TReturn, typename... TArgs>
constexpr size_t function_traits<TReturn(*)(TArgs...)>::argument_count;
struct function_traits<TReturn(*)(TArgs...), void> : function_traits<TReturn(TArgs...)> {};
//***************************************************************************
/// Specialisation for member function pointers
// Free function reference
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn(TObject::*)(TArgs...)>
template <typename TReturn, typename... TArgs>
struct function_traits<TReturn(&)(TArgs...), void> : function_traits<TReturn(TArgs...)> {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
//***************************************************************************
// Free noexcept function pointer
//***************************************************************************
template <typename TReturn, typename... TArgs>
struct function_traits<TReturn(*)(TArgs...) noexcept, void> : function_traits<TReturn(TArgs...)>
{
using function_type = TReturn(TArgs...); ///< The signature of the function.
using return_type = TReturn; ///< The return type.
using object_type = TObject; ///< The object type, if a member function.
using argument_types = etl::type_list<TArgs...>; ///< An etl::type_list containing the function argument types.
static constexpr bool is_function = false; ///< <b>true</b> if the type is a free, static or global function, otherwise <b>false</b>.
static constexpr bool is_member_function = true; ///< <b>true</b> if the type is a member function, otherwise <b>false</b>.
static constexpr bool is_const = false; ///< <b>true</b> if the type is a const member function, otherwise <b>false</b>.
static constexpr size_t argument_count = sizeof...(TArgs); ///< The number of arguments that the function takes.
static constexpr bool is_noexcept = true;
};
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn(TObject::*)(TArgs...)>::is_function;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn(TObject::*)(TArgs...)>::is_member_function;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn(TObject::*)(TArgs...)>::is_const;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr size_t function_traits<TReturn(TObject::*)(TArgs...)>::argument_count;
//***************************************************************************
/// Specialisation for const member function pointers
// Free noexcept function reference.
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn(TObject::*)(TArgs...) const>
template <typename TReturn, typename... TArgs>
struct function_traits<TReturn(&)(TArgs...) noexcept, void> : function_traits<TReturn(TArgs...)>
{
using function_type = TReturn(TArgs...); ///< The signature of the function.
using return_type = TReturn; ///< The return type.
using object_type = TObject; ///< The object type, if a member function.
using argument_types = etl::type_list<TArgs...>; ///< An etl::type_list containing the function argument types.
static constexpr bool is_noexcept = true;
};
#endif
static constexpr bool is_function = false; ///< <b>true</b> if the type is a free, static or global function, otherwise <b>false</b>.
static constexpr bool is_member_function = true; ///< <b>true</b> if the type is a member function, otherwise <b>false</b>.
static constexpr bool is_const = true; ///< <b>true</b> if the type is a const member function, otherwise <b>false</b>.
static constexpr size_t argument_count = sizeof...(TArgs); ///< The number of arguments that the function takes.
//***************************************************************************
// Member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...), void> : function_traits<TReturn(TArgs...)>
{
using object_type = TObject;
static constexpr bool is_function = false;
static constexpr bool is_member_function = true;
};
//***************************************************************************
// Const member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn(TObject::*)(TArgs...) const>::is_function;
struct function_traits<TReturn (TObject::*)(TArgs...) const, void> : function_traits<TReturn(TObject::*)(TArgs...)>
{
static constexpr bool is_const = true;
};
//***************************************************************************
// Volatile member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...) volatile, void> : function_traits<TReturn(TObject::*)(TArgs...)>
{
static constexpr bool is_volatile = true;
};
//***************************************************************************
// Const volatile member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...) const volatile, void> : function_traits<TReturn(TObject::*)(TArgs...)>
{
static constexpr bool is_const = true;
static constexpr bool is_volatile = true;
};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
//***************************************************************************
// Noexcept member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...) noexcept, void> : function_traits<TReturn(TObject::*)(TArgs...)>
{
static constexpr bool is_noexcept = true;
};
//***************************************************************************
// Const noexcept member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...) const noexcept, void> : function_traits<TReturn(TObject::*)(TArgs...) const>
{
static constexpr bool is_noexcept = true;
};
//***************************************************************************
// Volatile noexcept member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...) volatile noexcept, void> : function_traits<TReturn(TObject::*)(TArgs...) volatile>
{
static constexpr bool is_noexcept = true;
};
//***************************************************************************
// Const volatile noexcept member function pointers
//***************************************************************************
template <typename TReturn, typename TObject, typename... TArgs>
struct function_traits<TReturn (TObject::*)(TArgs...) const volatile noexcept, void> : function_traits<TReturn(TObject::*)(TArgs...) const volatile>
{
static constexpr bool is_noexcept = true;
};
#endif
//***************************************************************************
// Forward cv/ref on the whole type to the unqualified type.
//***************************************************************************
template <typename T>
struct function_traits<T, etl::enable_if_t<!etl::is_same<T, etl::remove_cvref_t<T>>::value &&
!etl::is_class<etl::decay_t<T>>::value>>
: function_traits<etl::remove_cvref_t<T>>
{
};
//***************************************************************************
// Functors / lambdas: enable only for class types that have a unique operator()
//***************************************************************************
namespace private_function_traits
{
//*********************************
// Helper to get pointer to call operator
//*********************************
template <typename U>
using call_operator_ptr_t = decltype(&U::operator());
}
//***************************************************************************
/// Functors / lambdas specialisation
//***************************************************************************
template <typename T>
struct function_traits<T, etl::enable_if_t<etl::is_class<etl::decay_t<T>>::value&&
etl::has_unique_call_operator<T>::value>>
: function_traits<private_function_traits::call_operator_ptr_t<etl::decay_t<T>> >
{
static constexpr bool is_functor = true;
};
//***************************************************************************
// Out-of-class definitions for the function_traits static members
//***************************************************************************
// free/function primary template
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(TArgs...), void>::is_function;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(TArgs...), void>::is_member_function;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(TArgs...), void>::is_functor;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(TArgs...), void>::is_const;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(TArgs...), void>::is_volatile;
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(TArgs...), void>::is_noexcept;
template <typename TReturn, typename... TArgs>
constexpr size_t function_traits<TReturn(TArgs...), void>::arity;
// member-function-pointer specialization
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...), void>::is_function;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn(TObject::*)(TArgs...) const>::is_member_function;
constexpr bool function_traits<TReturn (TObject::*)(TArgs...), void>::is_member_function;
// cv/ref-qualified member-function pointer flags
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) const, void>::is_const;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) volatile, void>::is_volatile;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) const volatile, void>::is_const;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) const volatile, void>::is_volatile;
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename... TArgs>
constexpr bool function_traits<TReturn(*)(TArgs...) noexcept, void>::is_noexcept;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn(TObject::*)(TArgs...) const>::is_const;
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) noexcept, void>::is_noexcept;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr size_t function_traits<TReturn(TObject::*)(TArgs...) const>::argument_count;
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) const noexcept, void>::is_noexcept;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) volatile noexcept, void>::is_noexcept;
template <typename TReturn, typename TObject, typename... TArgs>
constexpr bool function_traits<TReturn (TObject::*)(TArgs...) const volatile noexcept, void>::is_noexcept;
#endif
//***************************************************************************
// Functor / lambda specialisation: provide out-of-class definition for is_functor
//***************************************************************************
template <typename T>
constexpr bool function_traits<T, etl::enable_if_t<etl::is_class<etl::decay_t<T>>::value &&
etl::has_unique_call_operator<T>::value>>::is_functor;
}
#endif
#endif
#endif

View File

@ -2571,10 +2571,13 @@ typedef integral_constant<bool, true> true_type;
// Plain / cv-qualified
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...)> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) volatile> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const volatile> : etl::true_type {};
@ -2582,18 +2585,41 @@ typedef integral_constant<bool, true> true_type;
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...)> : etl::true_type {};
// noexcept variants (if supported by the toolchain)
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) volatile> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const volatile> : etl::true_type {};
// noexcept variants (if supported)
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) volatile noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const volatile noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) volatile noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const volatile noexcept> : etl::true_type {};
#endif
#if ETL_USING_CPP17
@ -2679,26 +2705,74 @@ typedef integral_constant<bool, true> true_type;
//***************************************************************************
/// Is T a member function pointer
//***************************************************************************
namespace private_type_traits
{
// Primary: not a member function pointer.
template <typename T>
struct is_member_function_pointer_helper : etl::false_type
{
};
template <typename T> struct is_member_function_pointer : etl::false_type {};
// If the type is 'TMember TObject::*' then TMember is the member
// Uses etl::is_function<TMember> to detect member function pointers.
template <typename TMember, typename TObject>
struct is_member_function_pointer_helper<TMember TObject::*> : etl::is_function<TMember>
{
};
}
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...)> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile> : etl::true_type {};
template <typename T>
struct is_member_function_pointer : private_type_traits::is_member_function_pointer_helper<etl::remove_cv_t<T>>
{
};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile noexcept> : etl::true_type {};
#endif
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile &&>: etl::true_type {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile && noexcept>: etl::true_type {};
#endif
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...)> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile> : etl::true_type {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile noexcept> : etl::true_type {};
#endif
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile &&>: etl::true_type {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile && noexcept>: etl::true_type {};
#endif
#endif
#if ETL_USING_CPP17

View File

@ -325,6 +325,16 @@ SOFTWARE.
#define ETL_HAS_CHRONO_LITERALS_DURATION 1
#endif
//*************************************
// Indicate if noexcept is part of the function type.
#if !defined(ETL_HAS_NOEXCEPT_FUNCTION_TYPE)
#if defined(__cpp_noexcept_function_type) && (__cpp_noexcept_function_type >= 201510)
#define ETL_HAS_NOEXCEPT_FUNCTION_TYPE 1
#else
#define ETL_HAS_NOEXCEPT_FUNCTION_TYPE 0
#endif
#endif
//*************************************
// The macros below are dependent on the profile.
// C++11
@ -652,6 +662,7 @@ namespace etl
static ETL_CONSTANT bool has_chrono_literals_microseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1);
static ETL_CONSTANT bool has_chrono_literals_nanoseconds = (ETL_HAS_CHRONO_LITERALS_DURATION == 1);
static ETL_CONSTANT bool has_std_byteswap = (ETL_HAS_STD_BYTESWAP == 1);
static ETL_CONSTANT bool has_noexcept_function_type = (ETL_HAS_NOEXCEPT_FUNCTION_TYPE == 1);
// Is...
static ETL_CONSTANT bool is_debug_build = (ETL_IS_DEBUG_BUILD == 1);

View File

@ -2564,10 +2564,13 @@ typedef integral_constant<bool, true> true_type;
// Plain / cv-qualified
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...)> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) volatile> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const volatile> : etl::true_type {};
@ -2575,18 +2578,41 @@ typedef integral_constant<bool, true> true_type;
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...)> : etl::true_type {};
// noexcept variants (if supported by the toolchain)
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) volatile> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const volatile> : etl::true_type {};
// noexcept variants (if supported)
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) volatile noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs...) const volatile noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) volatile noexcept> : etl::true_type {};
template<typename TReturn, typename... TArgs>
struct is_function<TReturn(TArgs..., ...) const volatile noexcept> : etl::true_type {};
#endif
#if ETL_USING_CPP17
@ -2672,26 +2698,74 @@ typedef integral_constant<bool, true> true_type;
//***************************************************************************
/// Is T a member function pointer
//***************************************************************************
namespace private_type_traits
{
// Primary: not a member function pointer.
template <typename T>
struct is_member_function_pointer_helper : etl::false_type
{
};
template <typename T> struct is_member_function_pointer : etl::false_type {};
// If the type is 'TMember TObject::*' then TMember is the member
// Uses etl::is_function<TMember> to detect member function pointers.
template <typename TMember, typename TObject>
struct is_member_function_pointer_helper<TMember TObject::*> : etl::is_function<TMember>
{
};
}
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...)> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile> : etl::true_type {};
template <typename T>
struct is_member_function_pointer : private_type_traits::is_member_function_pointer_helper<etl::remove_cv_t<T>>
{
};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile noexcept> : etl::true_type {};
#endif
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile &&>: etl::true_type {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) volatile && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs...) const volatile && noexcept>: etl::true_type {};
#endif
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...)> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile> : etl::true_type {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile noexcept> : etl::true_type {};
#endif
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile &> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile &&> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile &&>: etl::true_type {};
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile & noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) volatile && noexcept> : etl::true_type {};
template <typename TReturn, typename TObject, typename... TArgs> struct is_member_function_pointer<TReturn(TObject::*)(TArgs..., ...) const volatile && noexcept>: etl::true_type {};
#endif
#endif
#if ETL_USING_CPP17

View File

@ -42,6 +42,13 @@ namespace
{
}
//*****************************************************************************
// The free noexcept function taking no parameters.
//*****************************************************************************
void free_void_noexcept() noexcept
{
}
//*****************************************************************************
// The free function taking an int parameter.
//*****************************************************************************
@ -67,6 +74,30 @@ namespace
{
}
void member_void_noexcept() noexcept
{
}
void member_void_const_noexcept() const noexcept
{
}
void member_void_volatile() volatile
{
}
void member_void_volatile_noexcept() volatile noexcept
{
}
void member_void_const_volatile() const volatile
{
}
void member_void_const_volatile_noexcept() const volatile noexcept
{
}
//*******************************************
// int
int member_int(int i, int j)
@ -86,6 +117,16 @@ namespace
(void)j;
}
};
//*****************************************************************************
// A functor with a unique operator()
//*****************************************************************************
struct Functor { int operator()(int x) { return x + 1; } };
//*****************************************************************************
// A functor with a unique operator()
//*****************************************************************************
struct FunctorConst { int operator()(int x) const { return x + 1; } };
}
namespace
@ -106,8 +147,30 @@ namespace
CHECK_TRUE(traits::is_function);
CHECK_FALSE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_EQUAL(0, traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_free_function_free_void_noexcept)
{
free_void_noexcept(); // Keep clang happy
using traits = etl::function_traits<decltype(&free_void_noexcept)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<void, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_TRUE(traits::is_function);
CHECK_FALSE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_FALSE(traits::is_volatile);
}
//*************************************************************************
@ -124,8 +187,11 @@ namespace
CHECK_TRUE(traits::is_function);
CHECK_FALSE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_EQUAL(2 , traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(2, traits::arity);
}
//*************************************************************************
@ -140,8 +206,11 @@ namespace
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_EQUAL(0, traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
@ -156,8 +225,141 @@ namespace
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_TRUE(traits::is_const);
CHECK_EQUAL(0, traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_member_function_void_noexcept)
{
using traits = etl::function_traits<decltype(&Object::member_void_noexcept)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<Object, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_FALSE(traits::is_volatile);
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
CHECK_TRUE(traits::is_noexcept);
#else
CHECK_FALSE(traits::is_noexcept);
#endif
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_member_function_void_const_noexcept)
{
using traits = etl::function_traits<decltype(&Object::member_void_const_noexcept)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<Object, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_TRUE(traits::is_const);
CHECK_FALSE(traits::is_volatile);
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
CHECK_TRUE(traits::is_noexcept);
#else
CHECK_FALSE(traits::is_noexcept);
#endif
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_member_function_void_volatile)
{
using traits = etl::function_traits<decltype(&Object::member_void_volatile)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<Object, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_TRUE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_member_function_void_const_volatile)
{
using traits = etl::function_traits<decltype(&Object::member_void_const_volatile)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<Object, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_TRUE(traits::is_const);
CHECK_TRUE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_member_function_void_volatile_noexcept)
{
using traits = etl::function_traits<decltype(&Object::member_void_volatile_noexcept)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<Object, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_TRUE(traits::is_volatile);
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
CHECK_TRUE(traits::is_noexcept);
#else
CHECK_FALSE(traits::is_noexcept);
#endif
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
TEST(test_member_function_void_const_volatile_noexcept)
{
using traits = etl::function_traits<decltype(&Object::member_void_const_volatile_noexcept)>;
CHECK_TRUE((std::is_same<void(void), traits::function_type>::value));
CHECK_TRUE((std::is_same<void, traits::return_type>::value));
CHECK_TRUE((std::is_same<Object, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_TRUE(traits::is_const);
CHECK_TRUE(traits::is_volatile);
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
CHECK_TRUE(traits::is_noexcept);
#else
CHECK_FALSE(traits::is_noexcept);
#endif
CHECK_EQUAL(0, traits::arity);
}
//*************************************************************************
@ -172,8 +374,11 @@ namespace
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_EQUAL(2, traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(2, traits::arity);
}
//*************************************************************************
@ -188,8 +393,11 @@ namespace
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_TRUE(traits::is_const);
CHECK_EQUAL(2, traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(2, traits::arity);
}
//*************************************************************************
@ -204,8 +412,123 @@ namespace
CHECK_TRUE(traits::is_function);
CHECK_FALSE(traits::is_member_function);
CHECK_FALSE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_EQUAL(1, traits::argument_count);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(1, traits::arity);
}
//*************************************************************************
TEST(test_lambda)
{
auto lambda = [](int a, const std::string& s) -> long { return static_cast<long>(a + s.size()); };
using traits = etl::function_traits<decltype(lambda)>;
CHECK_TRUE((std::is_same<long(int, const std::string&), traits::function_type>::value));
CHECK_TRUE((std::is_same<long, traits::return_type>::value));
CHECK_TRUE((std::is_same<decltype(lambda), traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<int, const std::string&>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_TRUE(traits::is_functor);
CHECK_TRUE(traits::is_const);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(2, traits::arity);
}
//*************************************************************************
TEST(test_functor)
{
struct functor
{
long operator()(int a, const std::string& s)
{
return static_cast<long>(a + s.size());
};
};
using traits = etl::function_traits<functor>;
CHECK_TRUE((std::is_same<long(int, const std::string&), traits::function_type>::value));
CHECK_TRUE((std::is_same<long, traits::return_type>::value));
CHECK_TRUE((std::is_same<functor, traits::object_type>::value));
CHECK_TRUE((std::is_same<etl::type_list<int, const std::string&>, traits::argument_types>::value));
CHECK_FALSE(traits::is_function);
CHECK_TRUE(traits::is_member_function);
CHECK_TRUE(traits::is_functor);
CHECK_FALSE(traits::is_const);
CHECK_FALSE(traits::is_volatile);
CHECK_FALSE(traits::is_noexcept);
CHECK_EQUAL(2, traits::arity);
}
//*************************************************************************
// Forwarding of top-level cv/ref on the whole type to the unqualified type
TEST(test_function_traits_forward_cvref_free_ptr)
{
using ptr_t = decltype(&free_void);
using const_ptr_t = typename std::add_const<ptr_t>::type; // void(* const)()
using ref_ptr_t = ptr_t&; // void(*&)()
using traits_c = etl::function_traits<const_ptr_t>;
using traits_r = etl::function_traits<ref_ptr_t>;
CHECK_TRUE((std::is_same<void(void), traits_c::function_type>::value));
CHECK_TRUE((std::is_same<void(void), traits_r::function_type>::value));
CHECK_TRUE(traits_c::is_function);
CHECK_TRUE(traits_r::is_function);
CHECK_FALSE(traits_c::is_member_function);
CHECK_FALSE(traits_r::is_member_function);
}
//*************************************************************************
TEST(test_function_traits_forward_cvref_member_ptr)
{
using mptr_t = decltype(&Object::member_int);
using const_mptr_t = typename std::add_const<mptr_t>::type; // int (Object::* const)(int,int)
using ref_mptr_t = mptr_t&; // int (Object::*&)(int,int)
using traits_c = etl::function_traits<const_mptr_t>;
using traits_r = etl::function_traits<ref_mptr_t>;
CHECK_TRUE((std::is_same<int(int, int), traits_c::function_type>::value));
CHECK_TRUE((std::is_same<int(int, int), traits_r::function_type>::value));
CHECK_FALSE(traits_c::is_function);
CHECK_FALSE(traits_r::is_function);
CHECK_TRUE(traits_c::is_member_function);
CHECK_TRUE(traits_r::is_member_function);
CHECK_TRUE((std::is_same<Object, traits_c::object_type>::value));
CHECK_TRUE((std::is_same<Object, traits_r::object_type>::value));
}
//*************************************************************************
// Ensure function_traits resolves for Functor and const Functor
TEST(test_function_traits_functor_and_const_functor)
{
using traits_f = etl::function_traits<Functor>;
using traits_cf = etl::function_traits<FunctorConst>;
// Both should be recognized as functor types
CHECK_TRUE(traits_f::is_functor);
CHECK_TRUE(traits_cf::is_functor);
// The function_type should be int(int)
CHECK_TRUE((std::is_same<int(int), traits_f::function_type>::value));
CHECK_TRUE((std::is_same<int(int), traits_cf::function_type>::value));
// const Functor should be marked const
CHECK_FALSE(traits_f::is_const);
CHECK_TRUE(traits_cf::is_const);
CHECK_TRUE((std::is_same<Functor, traits_f::object_type>::value));
CHECK_TRUE((std::is_same<FunctorConst, traits_cf::object_type>::value));
CHECK_EQUAL(1, traits_f::arity);
CHECK_EQUAL(1, traits_cf::arity);
}
};
}

View File

@ -140,6 +140,67 @@ namespace
struct other_specialized
{
};
struct MF
{
int f(int) { return 0; }
int fc(int) const { return 0; }
int fv(int) volatile { return 0; }
int fcv(int) const volatile { return 0; }
#if ETL_USING_CPP11
int fl(int) & { return 0; }
int flc(int) const & { return 0; }
int flv(int) volatile & { return 0; }
int flcv(int) const volatile & { return 0; }
int fr(int) && { return 0; }
int frc(int) const && { return 0; }
int frv(int) volatile && { return 0; }
int frcv(int) const volatile && { return 0; }
#endif
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
int fn(int) noexcept { return 0; }
int fnc(int) const noexcept { return 0; }
int fnv(int) volatile noexcept { return 0; }
int fncv(int) const volatile noexcept { return 0; }
int fnl(int) & noexcept { return 0; }
int fnlc(int) const & noexcept { return 0; }
int fnlv(int) volatile & noexcept { return 0; }
int fnlcv(int) const volatile & noexcept { return 0; }
int fnr(int) && noexcept { return 0; }
int fnrc(int) const && noexcept { return 0; }
int fnrv(int) volatile && noexcept { return 0; }
int fnrcv(int) const volatile && noexcept { return 0; }
#endif
int fvar(int, ...) { return 0; }
int fvarc(int, ...) const { return 0; }
};
struct MO
{
int data;
};
static int f(int) { return 0; }
static int fvar(...) { return 0; }
static int fvar2(int, ...) { return 0; }
template <typename T, typename... TArgs>
static T ft(TArgs...) { return T(); }
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
static int fn(int) noexcept { return 0; }
static int fnvar(...) noexcept { return 0; }
static int fnvar2(int, ...) noexcept { return 0; }
template <typename T, typename... TArgs>
static T fnt(TArgs...) noexcept { return T(); }
#endif
}
// Definitions for when the STL and compiler built-ins are not available.
@ -1490,4 +1551,118 @@ namespace
CHECK_FALSE(c1);
}
#endif
//*************************************************************************
// Basic cv for member function pointers
TEST(test_is_member_function_pointer)
{
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::f)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fc)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fcv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fl)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::flc)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::flv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::flcv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fr)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::frc)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::frv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::frcv)>::value));
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fn)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnc)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fncv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnl)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnlc)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnlv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnlcv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnr)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnrc)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnrv)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fnrcv)>::value));
#endif
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fvar)>::value));
CHECK_TRUE((etl::is_member_function_pointer<decltype(&MF::fvarc)>::value));
}
//*************************************************************************
// Negative tests for member function pointer trait
TEST(test_is_member_function_pointer_negative)
{
(void)f(0);
// Free function pointer
CHECK_FALSE((etl::is_member_function_pointer<decltype(&f)>::value));
// Member object pointer
CHECK_FALSE((etl::is_member_function_pointer<int MF::*>::value));
// Plain function type (not pointer)
CHECK_FALSE((etl::is_member_function_pointer<int(int)>::value));
// Non-function type
CHECK_FALSE((etl::is_member_function_pointer<int>::value));
}
//*************************************************************************
// Member object pointer trait
TEST(test_is_member_object_pointer)
{
CHECK_TRUE((etl::is_member_object_pointer<int MO::*>::value));
// Not a member object pointer
CHECK_FALSE((etl::is_member_object_pointer<int (MF::*)(int)>::value));
CHECK_FALSE((etl::is_member_object_pointer<int*>::value));
}
//*************************************************************************
// Member pointer (either member object or member function pointer)
TEST(test_is_member_pointer_any)
{
CHECK_TRUE((etl::is_member_pointer<int MF::*>::value));
CHECK_TRUE((etl::is_member_pointer<int (MF::*)(int)>::value));
// Not member pointers
CHECK_FALSE((etl::is_member_pointer<int*>::value));
CHECK_FALSE((etl::is_member_pointer<decltype(f)>::value));
}
//*************************************************************************
// Function type detection
TEST(test_is_function)
{
(void)f(0);
(void)fvar();
(void)fvar2(0);
(void)ft<int, int, double>(0, 0.0);
CHECK_TRUE((etl::is_function<decltype(f)>::value));
CHECK_TRUE((etl::is_function<decltype(fvar)>::value));
CHECK_TRUE((etl::is_function<decltype(fvar2)>::value));
CHECK_TRUE((etl::is_function<decltype(ft<int, int, double>)>::value));
#if ETL_HAS_NOEXCEPT_FUNCTION_TYPE
(void)fn(0);
(void)fnvar();
(void)fnvar2(0);
(void)fnt<int, int, double>(0, 0.0);
CHECK_TRUE((etl::is_function<decltype(fn)>::value));
CHECK_TRUE((etl::is_function<decltype(fnvar)>::value));
CHECK_TRUE((etl::is_function<decltype(fnvar2)>::value));
CHECK_TRUE((etl::is_function<decltype(fnt<int, int, double>)>::value));
#endif
CHECK_FALSE((etl::is_function<int>::value));
CHECK_FALSE((etl::is_function<int*>::value));
CHECK_FALSE((etl::is_function<int MF::*>::value));
CHECK_FALSE((etl::is_function<int (MF::*)(int)>::value)); // pointer, not function
}
}