dlib C++ Library - type_traits.h

// Copyright (C) 2016 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_TYPE_TRAITS_H_
#define DLIB_TYPE_TRAITS_H_
/*
 This header contains back-ports of C++14/17 type traits
 It also contains aliases for things found in <type_traits> which
 deprecate old dlib type traits.
*/
#include <type_traits>
#include <cstdint>
namespace dlib
{
// ----------------------------------------------------------------------------------------
 /*!A is_pointer_type
 This is a template where is_pointer_type<T>::value == true when T is a pointer
 type and false otherwise.
 !*/
 template <typename T>
 using is_pointer_type = std::is_pointer<T>;
// ----------------------------------------------------------------------------------------
 /*!A is_const_type
 This is a template where is_const_type<T>::value == true when T is a const 
 type and false otherwise.
 !*/
 template <typename T>
 using is_const_type = std::is_const<std::remove_reference_t<T>>;
// ----------------------------------------------------------------------------------------
 /*!A is_reference_type
 This is a template where is_const_type<T>::value == true when T is a reference 
 type and false otherwise.
 !*/
 template <typename T>
 using is_reference_type = std::is_reference<std::remove_const_t<T>>;
// ----------------------------------------------------------------------------------------
 /*!A is_function 
 
 This is a template that allows you to determine if the given type is a function.
 For example,
 void funct();
 is_function<funct>::value == true
 is_function<int>::value == false 
 !*/
 template<typename T>
 using is_function = std::is_function<T>;
// ----------------------------------------------------------------------------------------
 /*!A is_same_type 
 This is a template where is_same_type<T,U>::value == true when T and U are the
 same type and false otherwise. 
 !*/
 template <typename T, typename U>
 using is_same_type = std::is_same<T,U>;
// ----------------------------------------------------------------------------------------
 /*!A And
 This template takes a list of bool values and yields their logical and. E.g.
 And<true,true,true>::value == true
 And<true,false,true>::value == false 
 !*/
#ifdef __cpp_fold_expressions
 template<bool... v>
 struct And : std::integral_constant<bool, (... && v)> {};
#else
 template<bool First, bool... Rest>
 struct And : std::integral_constant<bool, First && And<Rest...>::value> {};
 template<bool Value>
 struct And<Value> : std::integral_constant<bool, Value>{};
#endif
// ----------------------------------------------------------------------------------------
 /*!A Or 
 This template takes a list of bool values and yields their logical or. E.g.
 Or<true,true,true>::value == true
 Or<true,false,true>::value == true 
 Or<false,false,false>::value == false 
 !*/
#ifdef __cpp_fold_expressions
 template<bool... v>
 struct Or : std::integral_constant<bool, (... || v)> {};
#else
 template<bool First, bool... Rest>
 struct Or : std::integral_constant<bool, First || Or<Rest...>::value> {};
 template<bool Value>
 struct Or<Value> : std::integral_constant<bool, Value>{};
#endif
// ----------------------------------------------------------------------------------------
 /*!A is_any_type 
 This is a template where is_any_type<T,Rest...>::value == true when T is 
 the same type as any one of the types in Rest... 
 !*/
 template <typename T, typename... Types>
 struct is_any_type : Or<std::is_same<T,Types>::value...> {};
// ----------------------------------------------------------------------------------------
 /*!A is_float_type
 This is a template that can be used to determine if a type is one of the built
 int floating point types (i.e. float, double, or long double).
 !*/
 template<typename T>
 using is_float_type = std::is_floating_point<T>;
// ----------------------------------------------------------------------------------------
 /*!A is_unsigned_type 
 This is a template where is_unsigned_type<T>::value == true when T is an unsigned
 scalar type and false when T is a signed scalar type.
 !*/
 template <typename T>
 using is_unsigned_type = std::is_unsigned<T>;
// ----------------------------------------------------------------------------------------
 /*!A is_signed_type 
 This is a template where is_signed_type<T>::value == true when T is a signed
 scalar type and false when T is an unsigned scalar type.
 !*/
 template <typename T>
 using is_signed_type = std::is_signed<T>;
// ----------------------------------------------------------------------------------------
 /*!A is_built_in_scalar_type
 
 This is a template that allows you to determine if the given type is a built
 in scalar type such as an int, char, float, short, etc.
 For example, is_built_in_scalar_type<char>::value == true
 For example, is_built_in_scalar_type<std::string>::value == false 
 !*/
 template <typename T> 
 using is_built_in_scalar_type = std::is_arithmetic<T>;
// ----------------------------------------------------------------------------------------
 /*!A is_byte
 
 Tells you if a type is one of the byte types in C++. E.g.
 is_byte<char>::value == true
 is_byte<int>::value == false 
 !*/
 template<class Byte>
 using is_byte = std::integral_constant<bool, std::is_same<Byte,char>::value
 || std::is_same<Byte,int8_t>::value
 || std::is_same<Byte,uint8_t>::value
#ifdef __cpp_lib_byte
 || std::is_same<Byte,std::byte>::value
#endif
 >;
// ----------------------------------------------------------------------------------------
 /*!A remove_cvref_t
 This is a template that takes a type and strips off any const, volatile, or reference
 qualifiers and gives you back the basic underlying type. So for example:
 remove_cvref_t<const int&> == int
 !*/
 template< class T >
 using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
 /*!A basic_type
 This is a template that takes a type and strips off any const, volatile, or reference
 qualifiers and gives you back the basic underlying type. So for example:
 basic_type<const int&>::type == int
 This is the same as remove_cvref_t and exists for backwards compatibility with older dlib clients,
 since basic_type has existed in dlib long before remove_cvref_t was added to the standard library.
 !*/
 template <typename T>
 struct basic_type { using type = remove_cvref_t<T>; };
// ----------------------------------------------------------------------------------------
 /*!A conjunction 
 
 Takes a list of type traits and gives you the logical AND of them. E.g.
 conjunction<is_same_type<int,int>, is_same_type<char,char>>::value == true
 conjunction<is_same_type<int,int>, is_same_type<char,float>>::value == false 
 !*/
 template<class...>
 struct conjunction : std::true_type {};
 template<class B1>
 struct conjunction<B1> : B1 {};
 template<class B1, class... Bn>
 struct conjunction<B1, Bn...> : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
// ----------------------------------------------------------------------------------------
 /*!A are_nothrow_move_constructible 
 
 A type trait class telling you if all the types given to it are no-throw move constructable.
 
 !*/
 template <typename ...Types>
 struct are_nothrow_move_constructible : And<std::is_nothrow_move_constructible<Types>::value...> {};
// ----------------------------------------------------------------------------------------
 /*!A are_nothrow_move_assignable 
 
 A type trait class telling you if all the types given to it are no-throw move assignable.
 
 !*/
 template <typename ...Types>
 struct are_nothrow_move_assignable : And<std::is_nothrow_move_assignable<Types>::value...> {};
// ----------------------------------------------------------------------------------------
 /*!A are_nothrow_copy_constructible 
 
 A type trait class telling you if all the types given to it are no-throw copy constructable.
 
 !*/
 template <typename ...Types>
 struct are_nothrow_copy_constructible : And<std::is_nothrow_copy_constructible<Types>::value...> {};
// ----------------------------------------------------------------------------------------
 /*!A are_nothrow_copy_assignable 
 
 A type trait class telling you if all the types given to it are no-throw copy assignable.
 
 !*/
 template <typename ...Types>
 struct are_nothrow_copy_assignable : And<std::is_nothrow_copy_assignable<Types>::value...> {};
// ----------------------------------------------------------------------------------------
 /*!A void_t 
 
 Just always the void type. Is useful in SFINAE expressions when the resulting type doesn't
 matter and you just need a place to put an expression where SFINAE can take effect.
 !*/
 template< class... >
 using void_t = void;
// ----------------------------------------------------------------------------------------
 namespace swappable_details
 {
 using std::swap;
 template<class T, class = void>
 struct swap_traits
 {
 constexpr static bool is_swappable{false};
 constexpr static bool is_nothrow{false};
 };
 template<class T>
 struct swap_traits<T, void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>>
 {
 constexpr static bool is_swappable{true};
 constexpr static bool is_nothrow{noexcept(swap(std::declval<T&>(), std::declval<T&>()))};
 };
 }
// ----------------------------------------------------------------------------------------
 /*!A is_swappable 
 
 A type trait telling you if T can be swapped by a global swap() function.
 I.e. if this would compile:
 T a, b;
 swap(a,b);
 Then is_swappable<T>::value == true. 
 !*/
 template<class T>
 using is_swappable = std::integral_constant<bool, swappable_details::swap_traits<T>::is_swappable>;
// ----------------------------------------------------------------------------------------
 /*!A is_nothrow_swappable 
 
 A type trait telling you if T can be swapped by a global swap() function that is declared noexcept 
 then is_nothrow_swappable<T>::value == true. 
 !*/
 template<class T>
 using is_nothrow_swappable = std::integral_constant<bool, swappable_details::swap_traits<T>::is_nothrow>;
// ----------------------------------------------------------------------------------------
 /*!A are_nothrow_swappable 
 
 A type trait telling you if a list of types are all no-throw swappable.
 !*/
 template <typename ...Types>
 struct are_nothrow_swappable : And<is_nothrow_swappable<Types>::value...> {};
// ----------------------------------------------------------------------------------------
 /*!A size_
 
 This is just a shorthand for making std::integral_constant of type size_t.
 !*/
 template<std::size_t I>
 using size_ = std::integral_constant<std::size_t, I>;
// ----------------------------------------------------------------------------------------
 /*!A is_convertible
 This is a template that can be used to determine if one type is convertible 
 into another type.
 For example:
 is_convertible<int,float>::value == true // because ints are convertible to floats
 is_convertible<int*,float>::value == false // because int pointers are NOT convertible to floats
 !*/
 template <typename from, typename to>
 using is_convertible = std::is_convertible<from, to>;
// ----------------------------------------------------------------------------------------
 namespace details
 {
 template<class T, class AlwaysVoid = void>
 struct is_complete_type_impl : std::false_type{};
 template<class T>
 struct is_complete_type_impl<T, void_t<decltype(sizeof(T))>> : std::true_type{};
 }
 /*!A is_complete_type
 This is a template that can be used to determine if a type is a complete type. 
 I.e. if T is a complete type then is_complete_type<T>::value == true.
 !*/
 template<class T>
 using is_complete_type = details::is_complete_type_impl<T>;
// ----------------------------------------------------------------------------------------
 namespace details
 {
 template<typename Void, template <class...> class Op, class... Args>
 struct is_detected_impl : std::false_type{};
 template<template <class...> class Op, class... Args>
 struct is_detected_impl<dlib::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
 }
 /*!A is_detected
 This is exactly the same as std::experimental::is_detected from library fundamentals v.
 It is a convenient way to test if the Args types satisfy some property, like having a certain
 member function. For example, say you wanted to know if a type had a .size() method. You 
 could define:
 template<typename T>
 using has_a_size_member_function = decltype(std::declval<T>().size());
 And then
 is_detected<has_a_size_member_function, int>::value == false
 is_detected<has_a_size_member_function, std::string>::value == true 
 !*/
 template<template <class...> class Op, class... Args>
 using is_detected = details::is_detected_impl<void, Op, Args...>;
// ----------------------------------------------------------------------------------------
 
 template<typename... T>
 struct types_ {};
 /*!
 WHAT THIS OBJECT REPRESENTS
 This is a type list. You can use this for general-purpose meta-programming
 and it's used to pass types to the switch_() function.
 !*/
// ----------------------------------------------------------------------------------------
 namespace details
 {
#if defined(__has_builtin)
#if __has_builtin(__type_pack_element)
 #define HAS_TYPE_PACK_ELEMENT 1
#endif
#endif
#if HAS_TYPE_PACK_ELEMENT
 template<std::size_t I, class... Ts>
 struct nth_type_impl { using type = __type_pack_element<I,Ts...>; };
#else
 template<std::size_t I, class... Ts>
 struct nth_type_impl;
 template<std::size_t I, class T0, class... Ts>
 struct nth_type_impl<I, T0, Ts...> { using type = typename nth_type_impl<I-1, Ts...>::type; };
 template<class T0, class... Ts>
 struct nth_type_impl<0, T0, Ts...> { using type = T0; };
#endif
 }
 template<std::size_t I, class... Ts>
 struct nth_type;
 /*!
 WHAT THIS OBJECT REPRESENTS
 This is a type trait for getting the n'th argument of a parameter pack.
 In particular, nth_type<n, some_types...>::type is the nth type in some_types.
 !*/
 template<std::size_t I, class... Ts>
 struct nth_type<I, types_<Ts...>> : details::nth_type_impl<I,Ts...> {};
 template<std::size_t I, class... Ts>
 struct nth_type : details::nth_type_impl<I,Ts...> {};
 template<std::size_t I, class... Ts>
 using nth_type_t = typename nth_type<I,Ts...>::type;
// ----------------------------------------------------------------------------------------
 namespace details
 {
 template<class AlwaysVoid, class F>
 struct callable_traits_impl
 {
 constexpr static bool is_callable = false;
 };
 template<class AlwaysVoid, class R, class... Args>
 struct callable_traits_impl<AlwaysVoid, R(Args...)>
 {
 using return_type = R;
 using args = types_<Args...>;
 constexpr static std::size_t nargs = sizeof...(Args);
 constexpr static bool is_callable = true;
 }; 
 template<class AlwaysVoid, class R, class... Args>
 struct callable_traits_impl<AlwaysVoid, R(*)(Args...)> 
 : public callable_traits_impl<AlwaysVoid, R(Args...)>{};
 template<class AlwaysVoid, class C, class R, class... Args>
 struct callable_traits_impl<AlwaysVoid, R(C::*)(Args...)> 
 : public callable_traits_impl<AlwaysVoid, R(Args...)>{};
 template<class AlwaysVoid, class C, class R, class... Args>
 struct callable_traits_impl<AlwaysVoid, R(C::*)(Args...) const> 
 : public callable_traits_impl<AlwaysVoid, R(Args...)>{};
 template<class F>
 struct callable_traits_impl<void_t<decltype(&std::decay_t<F>::operator())>, F>
 : public callable_traits_impl<void, decltype(&std::decay_t<F>::operator())>{};
 }
 
 template<class F>
 struct callable_traits : details::callable_traits_impl<void, F> {};
 /*!
 WHAT THIS OBJECT REPRESENTS
 This is a type trait for callable types.
 If the template parameter F is function pointer, functor or lambda then
 it provides the following types:
 return_type : the return type of the callable object
 args : a parameter pack packaged in a types_<> meta container containing
 all the function argument types
 It also provides the following static members:
 nargs : the number of function arguments
 is_callable : a boolean which determines whether F is callable. In this case, it is true
 
 If the template parameter F is not function-like object, then it provides:
 is_callable : false
 
 For example, a function type F with signature R(T1, T2, T3) has the following traits:
 callable_traits<F>::return_type == R
 callable_traits<F>::args == types_<T1,T2,T3>
 callable_traits<F>::nargs == 3
 callable_traits<F>::is_callable == true
 Another example:
 callable_traits<int>::is_callable == false
 callable_traits<int>::return_type == does not exist. Compile error
 callable_traits<int>::args == does not exist. Compile error
 callable_traits<int>::nargs == does not exist. Compile error
 !*/
 template<class Callable>
 using callable_args = typename callable_traits<Callable>::args;
 template<std::size_t I, class Callable>
 using callable_arg = nth_type_t<I, callable_args<Callable>>;
 
 template<class Callable>
 using callable_nargs = std::integral_constant<std::size_t, callable_traits<Callable>::nargs>;
 template<class Callable>
 using callable_return = typename callable_traits<Callable>::return_type;
 template<class F>
 using is_callable = std::integral_constant<bool, callable_traits<F>::is_callable>;
// ----------------------------------------------------------------------------------------
}
#endif //DLIB_TYPE_TRAITS_H_

AltStyle によって変換されたページ (->オリジナル) /