44// / @brief Metaprogramming, template variables and concepts
55// / @ingroup userver_universal
66
7+ #include < concepts>
78#include < iosfwd>
89#include < iterator>
910#include < optional>
@@ -34,39 +35,21 @@ using IsRange =
3435template <typename T>
3536using IteratorType = std::enable_if_t <IsDetected<IsRange, T>, decltype (begin(std::declval<T&>()))>;
3637
37- template <typename T, typename = void >
38- struct IsIterator : std::false_type {};
39-
40- template <typename T>
41- struct IsIterator <T, std::void_t <typename std::iterator_traits<T>::iterator_category>> : std::true_type {};
42-
4338template <typename T>
4439using RangeValueType = typename std::iterator_traits<DetectedType<IteratorType, T>>::value_type;
4540
4641template <typename T>
4742using OstreamWriteResult = decltype (std::declval<std::ostream&>() << std::declval<const std::remove_reference_t <T>&>());
4843
49- template <typename T, typename U>
50- using EqualityComparisonResult = decltype (std::declval<const T&>() == std::declval<const U&>());
51-
5244template <typename T>
5345using StdHashResult = decltype (std::hash<T>{}(std::declval<const T&>()));
5446
55- template <typename T>
56- using IsSizable = decltype (std::size(std::declval<T>()));
57-
58- template <typename T>
59- using ReserveResult = decltype (std::declval<T&>().reserve(1 ));
60-
6147template <typename T>
6248using AtResult = decltype (std::declval<const T&>().at(std::declval<typename T::key_type>()));
6349
6450template <typename T>
6551using SubscriptOperatorResult = decltype (std::declval<T>()[std::declval<typename T::key_type>()]);
6652
67- template <typename T>
68- using PushBackResult = decltype (std::declval<T&>().push_back({}));
69-
7053template <typename T>
7154struct IsFixedSizeContainer : std::false_type {};
7255
@@ -85,20 +68,21 @@ constexpr bool IsSingleRange() {
8568
8669} // namespace impl
8770
71+ // NOLINTBEGIN(readability-identifier-naming)
72+
8873template <typename T>
89- inline constexpr bool kIsVector = kIsInstantiationOf <std::vector, T>;
74+ concept kIsVector = kIsInstantiationOf <std::vector, T>;
9075
9176template <typename T>
92- inline constexpr bool kIsRange = IsDetected<impl::IsRange, T>;
77+ concept kIsRange = IsDetected<impl::IsRange, T>;
9378
9479// / Returns true if T is an ordered or unordered map or multimap
9580template <typename T>
96- inline constexpr bool
97- kIsMap = IsDetected<impl::IsRange, T> && IsDetected<impl::KeyType, T> && IsDetected<impl::MappedType, T>;
81+ concept kIsMap = IsDetected<impl::IsRange, T> && IsDetected<impl::KeyType, T> && IsDetected<impl::MappedType, T>;
9882
9983// / Returns true if T is a map (but not a multimap!)
10084template <typename T>
101- inline constexpr bool kIsUniqueMap =
85+ concept kIsUniqueMap =
10286 kIsMap <T> &&
10387 IsDetected<
10488 impl::SubscriptOperatorResult,
@@ -114,39 +98,38 @@ template <typename T>
11498using RangeValueType = DetectedType<impl::RangeValueType, T>;
11599
116100template <typename T>
117- inline constexpr bool kIsRecursiveRange = std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
101+ concept kIsRecursiveRange = std::is_same_v<DetectedType<impl::RangeValueType, T>, T>;
118102
119103template <typename T>
120- inline constexpr bool kIsIterator = impl::IsIterator <T>::value ;
104+ concept kIsIterator = requires { typename std::iterator_traits <T>::iterator_category; } ;
121105
122106template <typename T>
123- inline constexpr bool kIsOptional = kIsInstantiationOf <std::optional, T>;
107+ concept kIsOptional = kIsInstantiationOf <std::optional, T>;
124108
125109template <typename T>
126- inline constexpr bool kIsOstreamWritable = std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
110+ concept kIsOstreamWritable = std::is_same_v<DetectedType<impl::OstreamWriteResult, T>, std::ostream&>;
127111
128112template <typename T, typename U = T>
129- inline constexpr bool kIsEqualityComparable = std::is_same_v<DetectedType<impl::EqualityComparisonResult, T, U>, bool >;
113+ concept kIsEqualityComparable = std::equality_comparable_with< T, U>;
130114
131115template <typename T>
132- inline constexpr bool
133- kIsStdHashable = std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t > && kIsEqualityComparable <T>;
116+ concept kIsStdHashable = std::is_same_v<DetectedType<impl::StdHashResult, T>, std::size_t > && kIsEqualityComparable <T>;
134117
135118// / @brief Check if std::size is applicable to container
136119template <typename T>
137- inline constexpr bool kIsSizable = IsDetected<impl::IsSizable, T> ;
120+ concept kIsSizable = requires (T value) { std::size (value); } ;
138121
139122// / @brief Check if a container has `reserve`
140123template <typename T>
141- inline constexpr bool kIsReservable = IsDetected<impl::ReserveResult, T> ;
124+ concept kIsReservable = requires (T value) { value. reserve ( 1 ); } ;
142125
143126// / @brief Check if a container has 'push_back'
144127template <typename T>
145- inline constexpr bool kIsPushBackable = IsDetected<impl::PushBackResult, T> ;
128+ concept kIsPushBackable = requires (T value) { value. push_back ({}); } ;
146129
147130// / @brief Check if a container has fixed size (e.g. std::array)
148131template <typename T>
149- inline constexpr bool kIsFixedSizeContainer = impl::IsFixedSizeContainer<T>::value;
132+ concept kIsFixedSizeContainer = impl::IsFixedSizeContainer<T>::value;
150133
151134// / @brief Returns default inserter for a container
152135template <typename T>
@@ -160,6 +143,8 @@ auto Inserter(T& container) {
160143 }
161144}
162145
146+ // NOLINTEND(readability-identifier-naming)
147+
163148} // namespace meta
164149
165150USERVER_NAMESPACE_END
0 commit comments