#pragma once #include #if __has_include() #include #endif #if __cpp_lib_concepts < 202002L #include #include #include namespace stdx { inline namespace v1 { #if __cplusplus < 202002L // Before C++20 we can't use concepts directly, but we can still allow the // names to be used in constexpr contexts template constexpr auto integral = std::is_integral_v; template constexpr auto floating_point = std::is_floating_point_v; template constexpr auto signed_integral = integral and std::is_signed_v; template constexpr auto unsigned_integral = integral and std::is_unsigned_v; template constexpr auto convertible_to = std::is_convertible_v; template constexpr auto derived_from = std::is_base_of_v and std::is_convertible_v; template constexpr auto same_as = std::is_same_v and std::is_same_v; template constexpr auto same_as_unqualified = is_same_unqualified_v and is_same_unqualified_v; // NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) #define DETECTOR(name, expr) \ namespace detail::detect { \ template constexpr auto name = false; \ template \ constexpr auto name> = true; \ } // NOLINTEND(bugprone-macro-parentheses, cppcoreguidelines-macro-usage) DETECTOR(eq_compare, (std::declval() == std::declval())) DETECTOR(neq_compare, (std::declval() != std::declval())) template constexpr auto equality_comparable = detail::detect::eq_compare and detail::detect::neq_compare; DETECTOR(lt_compare, (std::declval() < std::declval())) DETECTOR(lte_compare, (std::declval() <= std::declval())) DETECTOR(gt_compare, (std::declval() > std::declval())) DETECTOR(gte_compare, (std::declval() >= std::declval())) template constexpr auto totally_ordered = equality_comparable and detail::detect::lt_compare and detail::detect::lte_compare and detail::detect::gt_compare and detail::detect::gte_compare; namespace detail::detect { template struct arg_list { template using invoke_result_t = std::invoke_result_t; }; template constexpr auto invocable = false; template constexpr auto invocable< F, Args, std::void_t>> = true; } // namespace detail::detect template constexpr auto invocable = detail::detect::invocable>; template constexpr auto predicate = invocable and std::is_convertible_v, bool>; template constexpr auto callable = is_callable_v; template typename TypeTrait> constexpr auto has_trait = TypeTrait::value; #undef DETECTOR template constexpr auto structural = is_structural_v; #else // After C++20, we can define concepts that are lacking in the library template concept integral = std::is_integral_v; template concept floating_point = std::is_floating_point_v; template concept signed_integral = integral and std::is_signed_v; template concept unsigned_integral = integral and std::is_unsigned_v; template concept convertible_to = std::is_convertible_v and requires { static_cast(std::declval()); }; template concept derived_from = std::is_base_of_v and std::is_convertible_v; template concept same_as = std::is_same_v and std::is_same_v; template concept same_as_unqualified = is_same_unqualified_v and is_same_unqualified_v; template concept equality_comparable = requires(T const &t) { { t == t } -> same_as; { t != t } -> same_as; }; namespace detail { template concept partially_ordered = requires(T const &t) { { t < t } -> same_as; { t <= t } -> same_as; { t > t } -> same_as; { t >= t } -> same_as; }; } // namespace detail template concept totally_ordered = equality_comparable and detail::partially_ordered; template concept invocable = requires(F &&f, Args &&...args) { std::invoke(std::forward(f), std::forward(args)...); }; namespace detail { template concept boolean_testable_impl = stdx::convertible_to; template concept boolean_testable = boolean_testable_impl and requires(B &&b) { { not std::forward(b) } -> boolean_testable_impl; }; } // namespace detail template concept predicate = invocable and detail::boolean_testable>; template concept callable = is_callable_v; template typename TypeTrait> concept has_trait = TypeTrait::value; template concept structural = is_structural_v; #endif } // namespace v1 } // namespace stdx #else // C++20 concept library exists, so use that namespace stdx { inline namespace v1 { using std::floating_point; using std::integral; using std::signed_integral; using std::unsigned_integral; using std::convertible_to; using std::derived_from; using std::same_as; using std::equality_comparable; using std::totally_ordered; using std::invocable; using std::predicate; template concept callable = is_callable_v; template typename TypeTrait> concept has_trait = TypeTrait::value; template concept same_as_unqualified = is_same_unqualified_v and is_same_unqualified_v; template concept structural = is_structural_v; } // namespace v1 } // namespace stdx #endif