451 lines
13 KiB
C++
451 lines
13 KiB
C++
|
//--------------------------------------
|
||
|
// utils/traits: Additional type traits
|
||
|
//--------------------------------------
|
||
|
//
|
||
|
// Copyright kennytm (auraHT Ltd.) 2011.
|
||
|
// Distributed under the Boost Software License, Version 1.0.
|
||
|
// (See accompanying file LICENSE_1_0.txt or copy at
|
||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||
|
|
||
|
/**
|
||
|
|
||
|
``<utils/traits.hpp>`` --- Additional type traits
|
||
|
=================================================
|
||
|
|
||
|
This module provides additional type traits and related functions, missing from
|
||
|
the standard library.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#ifndef TRAITS_HPP_9ALQFEFX7TO
|
||
|
#define TRAITS_HPP_9ALQFEFX7TO 1
|
||
|
|
||
|
#include <cstdlib>
|
||
|
#include <tuple>
|
||
|
#include <functional>
|
||
|
#include <type_traits>
|
||
|
|
||
|
#include <fplus/internal/meta.hpp>
|
||
|
|
||
|
namespace fplus {
|
||
|
|
||
|
// source: https://github.com/kennytm/utils
|
||
|
namespace utils {
|
||
|
|
||
|
#ifdef __GNUC__
|
||
|
#pragma GCC diagnostic push
|
||
|
#pragma GCC diagnostic ignored "-Weffc++"
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
.. macro:: DECLARE_HAS_TYPE_MEMBER(member_name)
|
||
|
|
||
|
This macro declares a template ``has_member_name`` which will check whether
|
||
|
a type member ``member_name`` exists in a particular type.
|
||
|
|
||
|
Example::
|
||
|
|
||
|
DECLARE_HAS_TYPE_MEMBER(result_type)
|
||
|
|
||
|
...
|
||
|
|
||
|
printf("%d\n", has_result_type< std::plus<int> >::value);
|
||
|
// ^ prints '1' (true)
|
||
|
printf("%d\n", has_result_type< double(*)() >::value);
|
||
|
// ^ prints '0' (false)
|
||
|
*/
|
||
|
#define DECLARE_HAS_TYPE_MEMBER(member_name) \
|
||
|
template <typename, typename = void> \
|
||
|
struct has_##member_name \
|
||
|
{ enum { value = false }; }; \
|
||
|
template <typename T> \
|
||
|
struct has_##member_name<T, typename std::enable_if<sizeof(typename T::member_name)||true>::type> \
|
||
|
{ enum { value = true }; };
|
||
|
|
||
|
/**
|
||
|
.. type:: struct utils::function_traits<F>
|
||
|
|
||
|
Obtain compile-time information about a function object *F*.
|
||
|
|
||
|
This template currently supports the following types:
|
||
|
|
||
|
* Normal function types (``R(T...)``), function pointers (``R(*)(T...)``)
|
||
|
and function references (``R(&)(T...)`` and ``R(&&)(T...)``).
|
||
|
* Member functions (``R(C::*)(T...)``)
|
||
|
* ``std::function<F>``
|
||
|
* Type of lambda functions, and any other types that has a unique
|
||
|
``operator()``.
|
||
|
* Type of ``std::mem_fn`` (only for GCC's libstdc++ and LLVM's libc++).
|
||
|
Following the C++ spec, the first argument will be a raw pointer.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
struct function_traits
|
||
|
: public function_traits<decltype(&T::operator())>
|
||
|
{};
|
||
|
|
||
|
namespace xx_impl
|
||
|
{
|
||
|
template <typename C, typename R, typename... A>
|
||
|
struct memfn_type
|
||
|
{
|
||
|
typedef typename std::conditional<
|
||
|
std::is_const<C>::value,
|
||
|
typename std::conditional<
|
||
|
std::is_volatile<C>::value,
|
||
|
R (C::*)(A...) const volatile,
|
||
|
R (C::*)(A...) const
|
||
|
>::type,
|
||
|
typename std::conditional<
|
||
|
std::is_volatile<C>::value,
|
||
|
R (C::*)(A...) volatile,
|
||
|
R (C::*)(A...)
|
||
|
>::type
|
||
|
>::type type;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
template <typename ReturnType, typename... Args>
|
||
|
struct function_traits<ReturnType(Args...)>
|
||
|
{
|
||
|
/**
|
||
|
.. type:: type result_type
|
||
|
|
||
|
The type returned by calling an instance of the function object type *F*.
|
||
|
*/
|
||
|
typedef ReturnType result_type;
|
||
|
|
||
|
/**
|
||
|
.. type:: type function_type
|
||
|
|
||
|
The function type (``R(T...)``).
|
||
|
*/
|
||
|
typedef ReturnType function_type(Args...);
|
||
|
|
||
|
/**
|
||
|
.. type:: type member_function_type<OwnerType>
|
||
|
|
||
|
The member function type for an *OwnerType* (``R(OwnerType::*)(T...)``).
|
||
|
*/
|
||
|
template <typename OwnerType>
|
||
|
using member_function_type = typename xx_impl::memfn_type<
|
||
|
typename std::remove_pointer<typename std::remove_reference<OwnerType>::type>::type,
|
||
|
ReturnType, Args...
|
||
|
>::type;
|
||
|
|
||
|
/**
|
||
|
.. data:: static const size_t arity
|
||
|
|
||
|
Number of arguments the function object will take.
|
||
|
*/
|
||
|
enum { arity = sizeof...(Args) };
|
||
|
|
||
|
/**
|
||
|
.. type:: type arg<n>::type
|
||
|
|
||
|
The type of the *n*-th argument.
|
||
|
*/
|
||
|
template <size_t i>
|
||
|
struct arg
|
||
|
{
|
||
|
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename... Args>
|
||
|
struct function_traits<ReturnType(*)(Args...)>
|
||
|
: public function_traits<ReturnType(Args...)>
|
||
|
{};
|
||
|
|
||
|
template <typename ClassType, typename ReturnType, typename... Args>
|
||
|
struct function_traits<ReturnType(ClassType::*)(Args...)>
|
||
|
: public function_traits<ReturnType(Args...)>
|
||
|
{
|
||
|
typedef ClassType& owner_type;
|
||
|
};
|
||
|
|
||
|
template <typename ClassType, typename ReturnType, typename... Args>
|
||
|
struct function_traits<ReturnType(ClassType::*)(Args...) const>
|
||
|
: public function_traits<ReturnType(Args...)>
|
||
|
{
|
||
|
typedef const ClassType& owner_type;
|
||
|
};
|
||
|
|
||
|
template <typename ClassType, typename ReturnType, typename... Args>
|
||
|
struct function_traits<ReturnType(ClassType::*)(Args...) volatile>
|
||
|
: public function_traits<ReturnType(Args...)>
|
||
|
{
|
||
|
typedef volatile ClassType& owner_type;
|
||
|
};
|
||
|
|
||
|
template <typename ClassType, typename ReturnType, typename... Args>
|
||
|
struct function_traits<ReturnType(ClassType::*)(Args...) const volatile>
|
||
|
: public function_traits<ReturnType(Args...)>
|
||
|
{
|
||
|
typedef const volatile ClassType& owner_type;
|
||
|
};
|
||
|
|
||
|
template <typename FunctionType>
|
||
|
struct function_traits<std::function<FunctionType>>
|
||
|
: public function_traits<FunctionType>
|
||
|
{};
|
||
|
|
||
|
#if defined(_GLIBCXX_FUNCTIONAL)
|
||
|
#define MEM_FN_SYMBOL_XX0SL7G4Z0J std::_Mem_fn
|
||
|
#elif defined(_LIBCPP_FUNCTIONAL)
|
||
|
#define MEM_FN_SYMBOL_XX0SL7G4Z0J std::__mem_fn
|
||
|
#endif
|
||
|
|
||
|
#ifdef MEM_FN_SYMBOL_XX0SL7G4Z0J
|
||
|
|
||
|
template <typename R, typename C>
|
||
|
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R C::*>>
|
||
|
: public function_traits<R(C*)>
|
||
|
{};
|
||
|
template <typename R, typename C, typename... A>
|
||
|
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...)>>
|
||
|
: public function_traits<R(C*, A...)>
|
||
|
{};
|
||
|
template <typename R, typename C, typename... A>
|
||
|
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) const>>
|
||
|
: public function_traits<R(const C*, A...)>
|
||
|
{};
|
||
|
template <typename R, typename C, typename... A>
|
||
|
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) volatile>>
|
||
|
: public function_traits<R(volatile C*, A...)>
|
||
|
{};
|
||
|
template <typename R, typename C, typename... A>
|
||
|
struct function_traits<MEM_FN_SYMBOL_XX0SL7G4Z0J<R(C::*)(A...) const volatile>>
|
||
|
: public function_traits<R(const volatile C*, A...)>
|
||
|
{};
|
||
|
|
||
|
#undef MEM_FN_SYMBOL_XX0SL7G4Z0J
|
||
|
#endif
|
||
|
|
||
|
template <typename T>
|
||
|
struct function_traits<T&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<const T&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<volatile T&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<const volatile T&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<T&&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<const T&&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<volatile T&&> : public function_traits<T> {};
|
||
|
template <typename T>
|
||
|
struct function_traits<const volatile T&&> : public function_traits<T> {};
|
||
|
|
||
|
|
||
|
#define FORWARD_RES_8QR485JMSBT \
|
||
|
typename std::conditional< \
|
||
|
std::is_lvalue_reference<R>::value, \
|
||
|
T&, \
|
||
|
typename std::remove_reference<T>::type&& \
|
||
|
>::type
|
||
|
|
||
|
/**
|
||
|
.. function:: auto utils::forward_like<Like, T>(T&& t) noexcept
|
||
|
|
||
|
Forward the reference *t* like the type of *Like*. That means, if *Like* is
|
||
|
an lvalue (reference), this function will return an lvalue reference of *t*.
|
||
|
Otherwise, if *Like* is an rvalue, this function will return an rvalue
|
||
|
reference of *t*.
|
||
|
|
||
|
This is mainly used to propagate the expression category (lvalue/rvalue) of
|
||
|
a member of *Like*, generalizing ``std::forward``.
|
||
|
*/
|
||
|
template <typename R, typename T>
|
||
|
FORWARD_RES_8QR485JMSBT forward_like(T&& input) noexcept
|
||
|
{
|
||
|
return static_cast<FORWARD_RES_8QR485JMSBT>(input);
|
||
|
}
|
||
|
|
||
|
#undef FORWARD_RES_8QR485JMSBT
|
||
|
|
||
|
/**
|
||
|
.. type:: struct utils::copy_cv<From, To>
|
||
|
|
||
|
Copy the CV qualifier between the two types. For example,
|
||
|
``utils::copy_cv<const int, double>::type`` will become ``const double``.
|
||
|
*/
|
||
|
template <typename From, typename To>
|
||
|
struct copy_cv
|
||
|
{
|
||
|
private:
|
||
|
typedef typename std::remove_cv<To>::type raw_To;
|
||
|
typedef typename std::conditional<std::is_const<From>::value,
|
||
|
const raw_To, raw_To>::type const_raw_To;
|
||
|
public:
|
||
|
/**
|
||
|
.. type:: type type
|
||
|
|
||
|
Result of cv-copying.
|
||
|
*/
|
||
|
typedef typename std::conditional<std::is_volatile<From>::value,
|
||
|
volatile const_raw_To, const_raw_To>::type type;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
.. type:: struct utils::pointee<T>
|
||
|
|
||
|
Returns the type by derefering an instance of *T*. This is a generalization
|
||
|
of ``std::remove_pointer``, that it also works with iterators.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
struct pointee
|
||
|
{
|
||
|
/**
|
||
|
.. type:: type type
|
||
|
|
||
|
Result of dereferencing.
|
||
|
*/
|
||
|
typedef typename std::remove_reference<decltype(*std::declval<T>())>::type type;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
.. function:: std::add_rvalue_reference<T>::type utils::rt_val<T>() noexcept
|
||
|
|
||
|
Returns a value of type *T*. It is guaranteed to do nothing and will not
|
||
|
throw a compile-time error, but using the returned result will cause
|
||
|
undefined behavior.
|
||
|
*/
|
||
|
template <typename T>
|
||
|
typename std::add_rvalue_reference<T>::type rt_val() noexcept
|
||
|
{
|
||
|
return std::move(*static_cast<T*>(nullptr));
|
||
|
}
|
||
|
|
||
|
#ifdef __GNUC__
|
||
|
#pragma GCC diagnostic pop
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
namespace fplus
|
||
|
{
|
||
|
namespace internal
|
||
|
{
|
||
|
template <typename>
|
||
|
struct is_std_function : std::false_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
struct is_std_function<std::function<T>> : std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
// Those traits are needed to not perform arity checks on a generic-lambd
|
||
|
// or a templated/overloaded operator()
|
||
|
template <typename T, typename = void>
|
||
|
struct has_function_traits : std::false_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
// There is a bug with GCC 7 when a std::function is passed as T.
|
||
|
// It produces an ambiguous call between this one and the std::function overload
|
||
|
// It's related to our void_t implementation, the C++14 compatible version does not
|
||
|
// work, whereas the C++17 one does...
|
||
|
//
|
||
|
// So, help GCC a bit with is_std_function
|
||
|
template <typename T>
|
||
|
struct has_function_traits<T,
|
||
|
std::enable_if_t<!is_std_function<T>::value,
|
||
|
void_t<decltype(&T::operator())>>>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename... Args>
|
||
|
struct has_function_traits<ReturnType(Args...)> : std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (*)(Args...)> : std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...)> : std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) const>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) volatile>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) const volatile>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...)&> : std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) const &>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) volatile&>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) const volatile&>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) &&>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) const &&>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) volatile&&>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename ReturnType, typename ClassType, typename... Args>
|
||
|
struct has_function_traits<ReturnType (ClassType::*)(Args...) const volatile&&>
|
||
|
: std::true_type
|
||
|
{
|
||
|
};
|
||
|
|
||
|
template <typename FunctionType>
|
||
|
struct has_function_traits<std::function<FunctionType>> : std::true_type
|
||
|
{
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|