@@ -123,83 +123,172 @@ namespace cmcpp
123123
124124// std::tuple_size and std::tuple_element specializations for result wrappers
125125// These are needed for std::apply to work with result_ok_wrapper/result_err_wrapper
126- // The wrappers act as single-element tuples containing their wrapped value
126+ // Wrappers for tuple types forward to the wrapped tuple
127+ // Wrappers for non-tuple types act as single-element tuples
127128namespace std
128129{
130+ // Helper to detect if type is tuple-like
131+ template <typename T, typename = void >
132+ struct is_tuple_like : std::false_type
133+ {
134+ };
135+
136+ template <typename T>
137+ struct is_tuple_like <T, std::void_t <decltype (std::tuple_size<T>::value)>> : std::true_type
138+ {
139+ };
140+
141+ // For tuple-wrapped types, forward the size
129142 template <typename T>
130- struct tuple_size <cmcpp::result_ok_wrapper<T>> : std::integral_constant<std::size_t , std::tuple_size_v<T>>
143+ struct tuple_size <cmcpp::result_ok_wrapper<T>> : std::conditional_t <
144+ is_tuple_like<T>::value,
145+ std::integral_constant<std::size_t , std::tuple_size_v<T>>,
146+ std::integral_constant<std::size_t , 1 >>
131147 {
132148 };
133149
150+ // For tuple-wrapped types, forward the element type; for non-tuple, return T
134151 template <std::size_t I, typename T>
135152 struct tuple_element <I, cmcpp::result_ok_wrapper<T>>
136153 {
137- using type = std::tuple_element_t <I, T>;
154+ using type = std::conditional_t <is_tuple_like<T>::value, std:: tuple_element_t <I, T> , T>;
138155 };
139156
140157 template <typename T>
141- struct tuple_size <cmcpp::result_err_wrapper<T>> : std::integral_constant<std::size_t , std::tuple_size_v<T>>
158+ struct tuple_size <cmcpp::result_err_wrapper<T>> : std::conditional_t <
159+ is_tuple_like<T>::value,
160+ std::integral_constant<std::size_t , std::tuple_size_v<T>>,
161+ std::integral_constant<std::size_t , 1 >>
142162 {
143163 };
144164
145165 template <std::size_t I, typename T>
146166 struct tuple_element <I, cmcpp::result_err_wrapper<T>>
147167 {
148- using type = std::tuple_element_t <I, T>;
168+ using type = std::conditional_t <is_tuple_like<T>::value, std:: tuple_element_t <I, T> , T>;
149169 };
150170}
151171
152172// std::get specializations for result wrappers to support structured bindings and std::apply
153- // Forward get<I> calls to the wrapped tuple
173+ // For tuple-wrapped types, forward get<I> calls to the wrapped tuple
174+ // For non-tuple types, return the value directly when I == 0
154175namespace std
155176{
177+ // result_ok_wrapper - tuple wrapped types
156178 template <std::size_t I, typename T>
157- constexpr decltype (auto ) get(cmcpp::result_ok_wrapper<T> &wrapper) noexcept
179+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<T &>()))>
180+ get (cmcpp::result_ok_wrapper<T> &wrapper) noexcept
158181 {
159182 return std::get<I>(wrapper.value );
160183 }
161184
162185 template <std::size_t I, typename T>
163- constexpr decltype (auto ) get(const cmcpp::result_ok_wrapper<T> &wrapper) noexcept
186+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<const T &>()))>
187+ get (const cmcpp::result_ok_wrapper<T> &wrapper) noexcept
164188 {
165189 return std::get<I>(wrapper.value );
166190 }
167191
168192 template <std::size_t I, typename T>
169- constexpr decltype (auto ) get(cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
193+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<T &&>()))>
194+ get (cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
170195 {
171196 return std::get<I>(std::move (wrapper.value ));
172197 }
173198
174199 template <std::size_t I, typename T>
175- constexpr decltype (auto ) get(const cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
200+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<const T &&>()))>
201+ get (const cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
176202 {
177203 return std::get<I>(std::move (wrapper.value ));
178204 }
179205
206+ // result_ok_wrapper - non-tuple wrapped types (I must be 0)
207+ template <std::size_t I, typename T>
208+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , T &>
209+ get (cmcpp::result_ok_wrapper<T> &wrapper) noexcept
210+ {
211+ return wrapper.value ;
212+ }
213+
214+ template <std::size_t I, typename T>
215+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , const T &>
216+ get (const cmcpp::result_ok_wrapper<T> &wrapper) noexcept
217+ {
218+ return wrapper.value ;
219+ }
220+
180221 template <std::size_t I, typename T>
181- constexpr decltype (auto ) get(cmcpp::result_err_wrapper<T> &wrapper) noexcept
222+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , T &&>
223+ get (cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
224+ {
225+ return std::move (wrapper.value );
226+ }
227+
228+ template <std::size_t I, typename T>
229+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , const T &&>
230+ get (const cmcpp::result_ok_wrapper<T> &&wrapper) noexcept
231+ {
232+ return std::move (wrapper.value );
233+ }
234+
235+ // result_err_wrapper - tuple wrapped types
236+ template <std::size_t I, typename T>
237+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<T &>()))>
238+ get (cmcpp::result_err_wrapper<T> &wrapper) noexcept
182239 {
183240 return std::get<I>(wrapper.value );
184241 }
185242
186243 template <std::size_t I, typename T>
187- constexpr decltype (auto ) get(const cmcpp::result_err_wrapper<T> &wrapper) noexcept
244+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<const T &>()))>
245+ get (const cmcpp::result_err_wrapper<T> &wrapper) noexcept
188246 {
189247 return std::get<I>(wrapper.value );
190248 }
191249
192250 template <std::size_t I, typename T>
193- constexpr decltype (auto ) get(cmcpp::result_err_wrapper<T> &&wrapper) noexcept
251+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<T &&>()))>
252+ get (cmcpp::result_err_wrapper<T> &&wrapper) noexcept
194253 {
195254 return std::get<I>(std::move (wrapper.value ));
196255 }
197256
198257 template <std::size_t I, typename T>
199- constexpr decltype (auto ) get(const cmcpp::result_err_wrapper<T> &&wrapper) noexcept
258+ constexpr std::enable_if_t <is_tuple_like<T>::value, decltype (std::get<I>(std::declval<const T &&>()))>
259+ get (const cmcpp::result_err_wrapper<T> &&wrapper) noexcept
200260 {
201261 return std::get<I>(std::move (wrapper.value ));
202262 }
263+
264+ // result_err_wrapper - non-tuple wrapped types (I must be 0)
265+ template <std::size_t I, typename T>
266+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , T &>
267+ get (cmcpp::result_err_wrapper<T> &wrapper) noexcept
268+ {
269+ return wrapper.value ;
270+ }
271+
272+ template <std::size_t I, typename T>
273+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , const T &>
274+ get (const cmcpp::result_err_wrapper<T> &wrapper) noexcept
275+ {
276+ return wrapper.value ;
277+ }
278+
279+ template <std::size_t I, typename T>
280+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , T &&>
281+ get (cmcpp::result_err_wrapper<T> &&wrapper) noexcept
282+ {
283+ return std::move (wrapper.value );
284+ }
285+
286+ template <std::size_t I, typename T>
287+ constexpr std::enable_if_t <!is_tuple_like<T>::value && I == 0 , const T &&>
288+ get (const cmcpp::result_err_wrapper<T> &&wrapper) noexcept
289+ {
290+ return std::move (wrapper.value );
291+ }
203292}
204293
205294#endif // CMCPP_MONOSTATE_HPP
0 commit comments