|
|
@@ -446,6 +446,14 @@ struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {}
|
|
|
template<typename Type>
|
|
|
inline constexpr bool is_complete_v = is_complete<Type>::value;
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Provides the member constant `value` to true if a given type is an
|
|
|
+ * iterator, false otherwise.
|
|
|
+ * @tparam Type The type to test.
|
|
|
+ */
|
|
|
+template<typename Type, typename = void>
|
|
|
+struct is_iterator: std::false_type {};
|
|
|
+
|
|
|
/**
|
|
|
* @cond TURN_OFF_DOXYGEN
|
|
|
* Internal details not to be documented.
|
|
|
@@ -454,10 +462,10 @@ inline constexpr bool is_complete_v = is_complete<Type>::value;
|
|
|
namespace internal {
|
|
|
|
|
|
template<typename, typename = void>
|
|
|
-struct is_iterator: std::false_type {};
|
|
|
+struct has_iterator_category: std::false_type {};
|
|
|
|
|
|
template<typename Type>
|
|
|
-struct is_iterator<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
|
|
+struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
|
|
|
|
|
} // namespace internal
|
|
|
|
|
|
@@ -466,18 +474,10 @@ struct is_iterator<Type, std::void_t<typename std::iterator_traits<Type>::iterat
|
|
|
* @endcond
|
|
|
*/
|
|
|
|
|
|
-/**
|
|
|
- * @brief Provides the member constant `value` to true if a given type is an
|
|
|
- * iterator, false otherwise.
|
|
|
- * @tparam Type The type to test.
|
|
|
- */
|
|
|
-template<typename Type, typename = void>
|
|
|
-struct is_iterator: std::false_type {};
|
|
|
-
|
|
|
/*! @copydoc is_iterator */
|
|
|
template<typename Type>
|
|
|
struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_pointer_t<Type>>, void>>>
|
|
|
- : internal::is_iterator<Type> {};
|
|
|
+ : internal::has_iterator_category<Type> {};
|
|
|
|
|
|
/**
|
|
|
* @brief Helper variable template.
|
|
|
@@ -548,6 +548,14 @@ struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::tr
|
|
|
template<typename Type>
|
|
|
inline constexpr bool is_transparent_v = is_transparent<Type>::value;
|
|
|
|
|
|
+/**
|
|
|
+ * @brief Provides the member constant `value` to true if a given type is
|
|
|
+ * equality comparable, false otherwise.
|
|
|
+ * @tparam Type The type to test.
|
|
|
+ */
|
|
|
+template<typename Type, typename = void>
|
|
|
+struct is_equality_comparable: std::false_type {};
|
|
|
+
|
|
|
/**
|
|
|
* @cond TURN_OFF_DOXYGEN
|
|
|
* Internal details not to be documented.
|
|
|
@@ -555,30 +563,40 @@ inline constexpr bool is_transparent_v = is_transparent<Type>::value;
|
|
|
|
|
|
namespace internal {
|
|
|
|
|
|
-template<typename>
|
|
|
-[[nodiscard]] constexpr bool is_equality_comparable(...) {
|
|
|
- return false;
|
|
|
-}
|
|
|
+template<typename, typename = void>
|
|
|
+struct has_tuple_size_value: std::false_type {};
|
|
|
|
|
|
template<typename Type>
|
|
|
-[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) -> decltype(std::declval<Type>() == std::declval<Type>()) {
|
|
|
+struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
|
|
|
+
|
|
|
+template<typename Type, std::size_t... Index>
|
|
|
+[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
|
|
|
+ return (is_equality_comparable<std::tuple_element_t<Index, Type>>::value && ...);
|
|
|
+}
|
|
|
+
|
|
|
+template<typename>
|
|
|
+[[nodiscard]] constexpr bool maybe_equality_comparable(choice_t<0>) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
template<typename Type>
|
|
|
-[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), std::declval<Type>() == std::declval<Type>()) {
|
|
|
+[[nodiscard]] constexpr auto maybe_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), bool{}) {
|
|
|
if constexpr(is_iterator_v<Type>) {
|
|
|
return true;
|
|
|
} else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
|
|
|
- return is_equality_comparable<Type>(choice<0>);
|
|
|
+ return maybe_equality_comparable<Type>(choice<0>);
|
|
|
} else {
|
|
|
- return is_equality_comparable<typename Type::value_type>(choice<2>);
|
|
|
+ return is_equality_comparable<typename Type::value_type>::value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
template<typename Type>
|
|
|
-[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) -> decltype(std::declval<typename Type::mapped_type>(), std::declval<Type>() == std::declval<Type>()) {
|
|
|
- return is_equality_comparable<typename Type::key_type>(choice<2>) && is_equality_comparable<typename Type::mapped_type>(choice<2>);
|
|
|
+[[nodiscard]] constexpr std::enable_if_t<is_complete_v<std::tuple_size<std::remove_const_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
|
|
|
+ if constexpr(has_tuple_size_value<Type>::value) {
|
|
|
+ return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
|
|
|
+ } else {
|
|
|
+ return maybe_equality_comparable<Type>(choice<1>);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
} // namespace internal
|
|
|
@@ -588,13 +606,10 @@ template<typename Type>
|
|
|
* @endcond
|
|
|
*/
|
|
|
|
|
|
-/**
|
|
|
- * @brief Provides the member constant `value` to true if a given type is
|
|
|
- * equality comparable, false otherwise.
|
|
|
- * @tparam Type The type to test.
|
|
|
- */
|
|
|
-template<typename Type, typename = void>
|
|
|
-struct is_equality_comparable: std::bool_constant<internal::is_equality_comparable<Type>(choice<2>)> {};
|
|
|
+/*! @copydoc is_equality_comparable */
|
|
|
+template<typename Type>
|
|
|
+struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
|
|
|
+ : std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {};
|
|
|
|
|
|
/**
|
|
|
* @brief Helper variable template.
|