cpp-utils/include/type_traits.hpp
2022-06-23 17:26:19 +01:00

78 lines
2.3 KiB
C++

#pragma once
namespace util {
template <typename T, T V>
struct integral_constant {static constexpr T value = V;};
struct true_type : integral_constant<bool, true> {};
struct false_type : integral_constant<bool, false> {};
inline constexpr bool true_type_v = true_type::value;
inline constexpr bool false_type_v = false_type::value;
namespace detail {
template <class T> struct type_identity {
using type = T;
}; // or use std::type_identity (since C++20)
template <class T> // Note that `cv void&` is a substitution failure
auto try_add_lvalue_reference(int) -> type_identity<T &>;
template <class T> // Handle T = cv void case
auto try_add_lvalue_reference(...) -> type_identity<T>;
template <class T> auto try_add_rvalue_reference(int) -> type_identity<T &&>;
template <class T> auto try_add_rvalue_reference(...) -> type_identity<T>;
} // namespace detail
template <class T>
struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) {
};
template <class T>
struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) {
};
template <class T>
using add_rvalue_reference_t = typename add_rvalue_reference<T>::type;
template <class T> add_rvalue_reference_t<T> declval() noexcept {
#pragma clang diagnostic push
static_assert(false, "Calling declval is ill-formed, see N4892 [declval]/2.");
#pragma clang diagnostic pop
}
namespace detail {
template <class T>
auto test_returnable(int)
-> decltype(void(static_cast<T (*)()>(nullptr)), true_type{});
template <class> auto test_returnable(...) -> false_type;
template <class From, class To>
auto test_implicitly_convertible(int)
-> decltype(void(declval<void (&)(To)>()(declval<From>())),
true_type{});
template <class, class>
auto test_implicitly_convertible(...) -> false_type;
} // namespace detail
template <typename T>
struct is_void : false_type{};
template<>
struct is_void<void> : true_type {};
template <typename T>
inline constexpr bool is_void_v = is_void<T>::value;
template< class T > struct remove_reference { typedef T type; };
template< class T > struct remove_reference<T&> { typedef T type; };
template< class T > struct remove_reference<T&&> { typedef T type; };
template< class T >
using remove_reference_t = typename remove_reference<T>::type;
}