#pragma once namespace util { template struct integral_constant {static constexpr T value = V;}; struct true_type : integral_constant {}; struct false_type : integral_constant {}; inline constexpr bool true_type_v = true_type::value; inline constexpr bool false_type_v = false_type::value; namespace detail { template struct type_identity { using type = T; }; // or use std::type_identity (since C++20) template // Note that `cv void&` is a substitution failure auto try_add_lvalue_reference(int) -> type_identity; template // Handle T = cv void case auto try_add_lvalue_reference(...) -> type_identity; template auto try_add_rvalue_reference(int) -> type_identity; template auto try_add_rvalue_reference(...) -> type_identity; } // namespace detail template struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference(0)) { }; template struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference(0)) { }; template using add_rvalue_reference_t = typename add_rvalue_reference::type; template add_rvalue_reference_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 auto test_returnable(int) -> decltype(void(static_cast(nullptr)), true_type{}); template auto test_returnable(...) -> false_type; template auto test_implicitly_convertible(int) -> decltype(void(declval()(declval())), true_type{}); template auto test_implicitly_convertible(...) -> false_type; } // namespace detail template struct is_void : false_type{}; template<> struct is_void : true_type {}; template inline constexpr bool is_void_v = is_void::value; template< class T > struct remove_reference { typedef T type; }; template< class T > struct remove_reference { typedef T type; }; template< class T > struct remove_reference { typedef T type; }; template< class T > using remove_reference_t = typename remove_reference::type; }