diff --git a/type.hpp b/type.hpp index 7a8d32d..62ef754 100644 --- a/type.hpp +++ b/type.hpp @@ -19,15 +19,6 @@ template struct remove_reference { using type = T; }; template struct remove_reference { using type = T; }; template using remove_reference_t = typename remove_reference::type; -namespace detail { - - template struct type_identity { using type = T; }; - - template auto try_add_pointer(int) -> type_identity *>; - template auto try_add_pointer(...) -> type_identity; - -} // namespace detail - template struct integral_constant { static constexpr T value = v; @@ -40,20 +31,6 @@ template using bool_constant = integral_constant; using false_type = bool_constant; using true_type = bool_constant; -template struct conditional { using type = T; }; -template struct conditional { using type = F; }; -template using conditional_t = typename conditional::type; - -template struct is_array : false_type {}; -template struct is_array : true_type {}; -template struct is_array : true_type {}; -template inline constexpr bool is_array_v = is_array::value; - -template struct remove_extent { using type = T; }; -template struct remove_extent { using type = T; }; -template struct remove_extent { using type = T; }; -template using remove_extent_t = typename remove_extent::type; - template struct is_const : false_type {}; template struct is_const : true_type {}; template inline constexpr bool is_const_v = is_const::value; @@ -70,9 +47,66 @@ template inline constexpr bool is_lvalue_reference_v = is_lvalue_re template struct is_function : integral_constant && !is_reference_v> {}; template inline constexpr bool is_function_v = is_function::value; +// Must use intrinsic, because this cannot be implemented in standard C++ +template struct is_union : integral_constant {}; +template inline constexpr bool is_union_v = is_union::value; + +namespace detail { + + template struct type_identity { using type = T; }; + + template auto try_add_pointer(int) -> type_identity *>; + template auto try_add_pointer(...) -> type_identity; + + template auto try_add_lvalue_reference(int) -> type_identity; + template auto try_add_lvalue_reference(...) -> type_identity; + + template auto try_add_rvalue_reference(int) -> type_identity; + template auto try_add_rvalue_reference(...) -> type_identity; + + template struct is_pointer_helper : false_type {}; + template struct is_pointer_helper : true_type {}; + + template struct is_member_pointer_helper : false_type {}; + template struct is_member_pointer_helper : true_type {}; + + template struct is_member_function_pointer_helper : false_type {}; + template struct is_member_function_pointer_helper : is_function {}; + + template integral_constant::value> is_class_helper(int T::*); + template false_type is_class_helper(...); + + template true_type test_pre_ptr_convertible(const volatile B *); + template false_type test_pre_ptr_convertible(const volatile void *); + + template auto test_pre_is_base_of(...) -> true_type; + template auto test_pre_is_base_of(int) -> decltype(test_pre_ptr_convertible(static_cast(nullptr))); + +} // namespace detail + +template struct conditional { using type = T; }; +template struct conditional { using type = F; }; +template using conditional_t = typename conditional::type; + +template struct is_array : false_type {}; +template struct is_array : true_type {}; +template struct is_array : true_type {}; +template inline constexpr bool is_array_v = is_array::value; + +template struct remove_extent { using type = T; }; +template struct remove_extent { using type = T; }; +template struct remove_extent { using type = T; }; +template using remove_extent_t = typename remove_extent::type; + template struct add_pointer : decltype(detail::try_add_pointer(0)) {}; template using add_pointer_t = typename add_pointer::type; +template struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference(0)) {}; +template using add_lvalue_reference_t = typename add_lvalue_reference::type; + +template struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference(0)) {}; +template using add_rvalue_reference_t = typename add_rvalue_reference::type; + template struct remove_cv { using type = T; }; template struct remove_cv { using type = T; }; template struct remove_cv { using type = T; }; @@ -85,6 +119,9 @@ template using remove_cv_t = typename remove_cv::type; template using remove_const_t = typename remove_const::type; template using remove_volatile_t = typename remove_volatile::type; +template struct remove_cvref { using type = remove_cv_t>; }; +template using remove_cvref_t = typename remove_cvref::type; + template struct decay { private: @@ -132,6 +169,142 @@ struct is_integral : integral_constant inline constexpr auto is_integral_v = is_integral::value; +template struct is_arithmetic : integral_constant::value || is_floating_point::value> {}; +template inline constexpr bool is_arithmetic_v = is_arithmetic::value; + +template struct is_void : is_same> {}; +template inline constexpr bool is_void_v = is_void::value; + +template struct is_pointer : detail::is_pointer_helper> {}; +template inline constexpr bool is_pointer_v = is_pointer::value; + +template struct is_member_pointer : detail::is_member_pointer_helper> {}; +template inline constexpr bool is_member_pointer_v = is_member_pointer::value; + +template struct is_member_function_pointer : detail::is_member_function_pointer_helper> {}; +template inline constexpr bool is_member_function_pointer_v = is_member_function_pointer::value; + +template struct is_member_object_pointer : integral_constant && !is_member_function_pointer_v> {}; +template inline constexpr bool is_member_object_pointer_v = is_member_object_pointer::value; + +template struct is_class : decltype(detail::is_class_helper(nullptr)) {}; +template inline constexpr bool is_class_v = is_class::value; + +template struct is_enum : integral_constant && + !is_integral_v && + !is_floating_point_v && + !is_array_v && + !is_pointer_v && + !is_reference_v && + !is_member_pointer_v && + !is_union_v && + !is_class_v && + !is_function_v> +{}; +template inline constexpr bool is_enum_v = is_enum::value; + +template struct is_null_pointer : is_same> {}; +template inline constexpr bool is_null_pointer_v = is_null_pointer::value; + +template +struct is_scalar : integral_constant || + is_enum_v || + is_pointer_v || + is_member_pointer_v || + is_null_pointer_v> +{}; +template inline constexpr bool is_scalar_v = is_scalar::value; + +template struct is_object : integral_constant || + is_array_v || + is_union_v || + is_class_v> +{}; +template inline constexpr bool is_object_v = is_object::value; + +template struct is_base_of : integral_constant && + is_class_v && + decltype(detail::test_pre_is_base_of(0))::value> +{}; +template inline constexpr bool is_base_of_v = is_base_of::value; + +template struct enable_if {}; +template struct enable_if { using type = T; }; +template using enable_if_t = typename enable_if::type; + +} // namespace type + +////////////////////////////////////////////////////////////////////////// +// Forward declarations + +namespace util { + +template struct reference_wrapper; +template inline constexpr T &&forward(type::remove_reference_t &t) noexcept; +template type::add_rvalue_reference_t declval() noexcept; + +} // namespace util + +////////////////////////////////////////////////////////////////////////// + +namespace type { + +// Everything is nothrow_invocable, because exceptions are disabled in avr-gcc +template struct is_nothrow_invocable : true_type {}; +template inline constexpr auto is_nothrow_invocable_v = is_nothrow_invocable::value; + +namespace detail { + +template struct is_reference_wrapper : false_type {}; +template struct is_reference_wrapper> : true_type {}; + +template +struct invoke_impl { + template + static auto call(Fn &&f, Args &&... args) -> decltype(util::forward(f)(util::forward(args)...)); +}; + +template +struct invoke_impl { + template , typename = enable_if_t>> + static auto get(T &&t) -> T &&; + + template , typename = enable_if_t::value>> + static auto get(T &&t) -> decltype(t.get()); + + template , + typename = enable_if_t>, + typename = enable_if_t::value>> + static auto get(T &&t) -> decltype(*util::forward(t)); + + template >> + static auto call(MT1 B::*pmf, T &&t, Args &&... args) + -> decltype((invoke_impl::get(util::forward(t)).*pmf)(util::forward(args)...)); + + template + static auto call(MT B::*pmd, T &&t) -> decltype(invoke_impl::get(util::forward(t)).*pmd); +}; + +template > +auto INVOKE(Fn &&f, Args &&... args) + -> decltype(invoke_impl::call(util::forward(f), util::forward(args)...)); + +template struct invoke_result {}; +template +struct invoke_result(), util::declval()...))), Fn, Args...> { + using type = decltype(INVOKE(util::declval(), util::declval()...)); +}; + +} // namespace detail + +template struct invoke_result : detail::invoke_result {}; +template using invoke_result_t = typename invoke_result::type; + // Not part of , but very useful template struct always_false : false_type {}; template inline constexpr auto always_false_v = always_false::value;