33// / @file userver/utils/box.hpp
44// / @brief @copybrief utils::Box
55
6+ #include < concepts>
67#include < memory>
78#include < type_traits>
89#include < utility>
@@ -16,19 +17,16 @@ USERVER_NAMESPACE_BEGIN
1617
1718namespace utils {
1819
20+ template <typename T>
21+ class Box ;
22+
1923namespace impl {
2024
21- template <typename Self, typename ... Args >
22- inline constexpr bool kArgsAreNotSelf = (( sizeof ...(Args) > 1 ) || ... || ! std::is_same_v<std:: decay_t <Args>, Self>) ;
25+ template <typename T >
26+ struct IsBox : std::false_type {} ;
2327
24- template <bool Condition, template <typename ...> typename Trait, typename ... Args>
25- constexpr bool ConjunctionWithTrait () noexcept {
26- if constexpr (Condition) {
27- return Trait<Args...>::value;
28- } else {
29- return false ;
30- }
31- }
28+ template <typename ... Args>
29+ struct IsBox <Box<Args...>> : std::true_type {};
3230
3331} // namespace impl
3432
@@ -61,37 +59,22 @@ class Box {
6159 {}
6260
6361 // / Allocate a `T`, copying or moving @a arg.
64- template <
65- typename U = T,
66- std::enable_if_t <
67- impl::ConjunctionWithTrait<
68- // Protection against hiding special
69- // constructors.
70- impl::kArgsAreNotSelf <Box, U>,
71- // Only allow the implicit conversion to Box<T>
72- // if U is implicitly convertible to T. Also,
73- // support SFINAE.
74- std::is_convertible,
75- U&&,
76- T>(),
77- int > = 0 >
78- /* implicit*/ Box(U&& arg)
62+ template <typename U = T>
63+ // Protect against hiding special constructors.
64+ requires (!std::same_as<std::remove_cvref_t <U>, Box>) &&
65+ // Prevent infinite recursion from constructible_from in the next check.
66+ (!impl::IsBox<std::remove_cvref_t <U>>::value) &&
67+ // Prevent infinite recursion.
68+ (std::same_as<std::remove_cvref_t <U>, T> || !std::is_constructible_v<T, Box>) &&
69+ // Normal requirement.
70+ std::is_constructible_v<T, U>
71+ explicit (!std::convertible_to<U, T>) Box(U&& arg)
7972 : data_(std::make_unique<T>(std::forward<U>(arg)))
8073 {}
8174
8275 // / Allocate the value, emplacing it with the given @a args.
83- template <
84- typename ... Args,
85- std::enable_if_t <
86- impl::ConjunctionWithTrait<
87- // Protection against hiding special
88- // constructors.
89- impl::kArgsAreNotSelf <Box, Args...>,
90- // Support SFINAE.
91- std::is_constructible,
92- T,
93- Args&&...>(),
94- int > = 0 >
76+ template <typename ... Args>
77+ requires (sizeof ...(Args) >= 2 ) && std::is_constructible_v<T, Args...>
9578 explicit Box (Args&&... args)
9679 : data_(std::make_unique<T>(std::forward<Args>(args)...))
9780 {}
@@ -116,22 +99,8 @@ class Box {
11699 }
117100
118101 // / Assigns-through to the contained value.
119- template <
120- typename U = T,
121- std::enable_if_t <
122- impl::ConjunctionWithTrait< //
123- impl::ConjunctionWithTrait<
124- // Protection against hiding
125- // special constructors.
126- impl::kArgsAreNotSelf <Box, U>,
127- // Support SFINAE.
128- std::is_constructible,
129- T,
130- U>(),
131- std::is_assignable,
132- T&,
133- U>(),
134- int > = 0 >
102+ template <typename U = T>
103+ requires (!std::same_as<std::remove_cvref_t <U>, Box>) && std::is_assignable_v<T&, U>
135104 Box& operator =(U&& other) {
136105 if (data_) {
137106 *data_ = std::forward<U>(other);
0 commit comments