4949#include < utility>
5050#include < variant>
5151#include < vector>
52+ #include < vix/meta/traits.hpp>
5253
5354#if defined(__cpp_lib_expected) && __cpp_lib_expected >= 202202L
5455#include < expected>
@@ -70,11 +71,11 @@ namespace vix
7071 struct inspect_options ;
7172
7273 // / @brief Primary inspector template — specialize to teach inspect about your type.
73- template <typename T, typename = void >
74+ template <typename T, typename >
7475 struct inspector ;
7576
7677 // / @brief Field map template — specialize to register struct fields for reflection.
77- template <typename T, typename = void >
78+ template <typename T, typename >
7879 struct field_map ;
7980
8081 namespace detail
@@ -166,346 +167,6 @@ namespace vix
166167
167168 } // namespace demangle
168169
169- namespace traits
170- {
171-
172- // Streamable via operator<<
173- template <typename T, typename = void >
174- struct is_ostreamable : std::false_type
175- {
176- };
177- template <typename T>
178- struct is_ostreamable <T,
179- std::void_t <decltype (std::declval<std::ostream &>() << std::declval<const T &>())>>
180- : std::true_type
181- {
182- };
183- template <typename T>
184- inline constexpr bool is_ostreamable_v = is_ostreamable<T>::value;
185-
186- // String-like (atomic, not iterable)
187- template <typename T>
188- struct is_string_like : std::false_type
189- {
190- };
191- template <>
192- struct is_string_like <std::string> : std::true_type
193- {
194- };
195- template <>
196- struct is_string_like <std::string_view> : std::true_type
197- {
198- };
199- template <>
200- struct is_string_like <const char *> : std::true_type
201- {
202- };
203- template <>
204- struct is_string_like <char *> : std::true_type
205- {
206- };
207- template <>
208- struct is_string_like <std::wstring> : std::true_type
209- {
210- };
211- template <>
212- struct is_string_like <std::wstring_view> : std::true_type
213- {
214- };
215- template <>
216- struct is_string_like <const wchar_t *> : std::true_type
217- {
218- };
219- template <std::size_t N>
220- struct is_string_like <char [N]> : std::true_type
221- {
222- };
223- template <std::size_t N>
224- struct is_string_like <const char [N]> : std::true_type
225- {
226- };
227- template <typename T>
228- inline constexpr bool is_string_like_v = is_string_like<std::remove_cvref_t <T>>::value;
229-
230- // Range (iterable, not string)
231- template <typename T, typename = void >
232- struct is_range : std::false_type
233- {
234- };
235- template <typename T>
236- struct is_range <T, std::void_t <
237- decltype (std::begin(std::declval<const T &>())),
238- decltype(std::end(std::declval<const T &>()))>>
239- : std::bool_constant<!is_string_like_v<T>>
240- {
241- };
242- template <typename T>
243- inline constexpr bool is_range_v = is_range<T>::value;
244-
245- // Map-like (key_type + mapped_type)
246- template <typename T, typename = void >
247- struct is_map_like : std::false_type
248- {
249- };
250- template <typename T>
251- struct is_map_like <T, std::void_t <typename T::key_type, typename T::mapped_type>>
252- : std::true_type
253- {
254- };
255- template <typename T>
256- inline constexpr bool is_map_like_v = is_map_like<T>::value;
257-
258- // Tuple-like
259- template <typename T, typename = void >
260- struct is_tuple_like : std::false_type
261- {
262- };
263- template <typename T>
264- struct is_tuple_like <T, std::void_t <decltype (std::tuple_size<T>::value)>>
265- : std::true_type
266- {
267- };
268- template <>
269- struct is_tuple_like <std::string> : std::false_type
270- {
271- };
272- template <typename T>
273- inline constexpr bool is_tuple_like_v = is_tuple_like<std::remove_cvref_t <T>>::value;
274-
275- // Pair
276- template <typename T>
277- struct is_pair : std::false_type
278- {
279- };
280- template <typename A, typename B>
281- struct is_pair <std::pair<A, B>> : std::true_type
282- {
283- };
284- template <typename T>
285- inline constexpr bool is_pair_v = is_pair<std::remove_cvref_t <T>>::value;
286-
287- // Smart pointers
288- template <typename T>
289- struct is_unique_ptr : std::false_type
290- {
291- };
292- template <typename T, typename D>
293- struct is_unique_ptr <std::unique_ptr<T, D>> : std::true_type
294- {
295- };
296- template <typename T>
297- struct is_shared_ptr : std::false_type
298- {
299- };
300- template <typename T>
301- struct is_shared_ptr <std::shared_ptr<T>> : std::true_type
302- {
303- };
304- template <typename T>
305- struct is_weak_ptr : std::false_type
306- {
307- };
308- template <typename T>
309- struct is_weak_ptr <std::weak_ptr<T>> : std::true_type
310- {
311- };
312-
313- // Optional / variant / any
314- template <typename T>
315- struct is_optional : std::false_type
316- {
317- };
318- template <typename T>
319- struct is_optional <std::optional<T>> : std::true_type
320- {
321- };
322- template <typename T>
323- inline constexpr bool is_optional_v = is_optional<std::remove_cvref_t <T>>::value;
324-
325- template <typename T>
326- struct is_variant : std::false_type
327- {
328- };
329- template <typename ... Ts>
330- struct is_variant <std::variant<Ts...>> : std::true_type
331- {
332- };
333- template <typename T>
334- inline constexpr bool is_variant_v = is_variant<std::remove_cvref_t <T>>::value;
335-
336- template <typename T>
337- inline constexpr bool is_any_v = std::is_same_v<std::remove_cvref_t <T>, std::any>;
338-
339- // Chrono
340- template <typename T>
341- struct is_duration : std::false_type
342- {
343- };
344- template <typename Rep, typename Period>
345- struct is_duration <std::chrono::duration<Rep, Period>> : std::true_type
346- {
347- };
348- template <typename T>
349- inline constexpr bool is_duration_v = is_duration<std::remove_cvref_t <T>>::value;
350-
351- template <typename T>
352- struct is_time_point : std::false_type
353- {
354- };
355- template <typename C, typename D>
356- struct is_time_point <std::chrono::time_point<C, D>> : std::true_type
357- {
358- };
359- template <typename T>
360- inline constexpr bool is_time_point_v = is_time_point<std::remove_cvref_t <T>>::value;
361-
362- // Misc
363- template <typename T>
364- inline constexpr bool is_fs_path_v =
365- std::is_same_v<std::remove_cvref_t <T>, std::filesystem::path>;
366-
367- template <typename T>
368- struct is_ref_wrapper : std::false_type
369- {
370- };
371- template <typename T>
372- struct is_ref_wrapper <std::reference_wrapper<T>> : std::true_type
373- {
374- };
375- template <typename T>
376- inline constexpr bool is_ref_wrapper_v = is_ref_wrapper<std::remove_cvref_t <T>>::value;
377-
378- template <typename T>
379- inline constexpr bool is_nullptr_v =
380- std::is_same_v<std::remove_cvref_t <T>, std::nullptr_t >;
381-
382- template <typename T>
383- inline constexpr bool is_bool_v =
384- std::is_same_v<std::remove_cvref_t <T>, bool >;
385-
386- template <typename T>
387- inline constexpr bool is_char_v =
388- std::is_same_v<std::remove_cvref_t <T>, char > ||
389- std::is_same_v<std::remove_cvref_t <T>, signed char > ||
390- std::is_same_v<std::remove_cvref_t <T>, unsigned char > ||
391- std::is_same_v<std::remove_cvref_t <T>, wchar_t > ||
392- std::is_same_v<std::remove_cvref_t <T>, char8_t > ||
393- std::is_same_v<std::remove_cvref_t <T>, char16_t > ||
394- std::is_same_v<std::remove_cvref_t <T>, char32_t >;
395-
396- // Container adapters
397- template <typename T>
398- struct is_stack : std::false_type
399- {
400- };
401- template <typename T, typename C>
402- struct is_stack <std::stack<T, C>> : std::true_type
403- {
404- };
405- template <typename T>
406- struct is_queue : std::false_type
407- {
408- };
409- template <typename T, typename C>
410- struct is_queue <std::queue<T, C>> : std::true_type
411- {
412- };
413- template <typename T>
414- struct is_priority_queue : std::false_type
415- {
416- };
417- template <typename T, typename C, typename Cmp>
418- struct is_priority_queue <std::priority_queue<T, C, Cmp>> : std::true_type
419- {
420- };
421-
422- // ADL vix_inspect detection
423- template <typename T, typename = void >
424- struct has_vix_inspect_hook : std::false_type
425- {
426- };
427- template <typename T>
428- struct has_vix_inspect_hook <T, std::void_t <
429- decltype (vix_inspect(std::declval<inspect_context &>(), std::declval<const T &>()))>>
430- : std::true_type
431- {
432- };
433- template <typename T>
434- inline constexpr bool has_vix_inspect_hook_v =
435- has_vix_inspect_hook<std::remove_cvref_t <T>>::value;
436-
437- // inspector<T> specialization detection
438- template <typename T, typename = void >
439- struct has_inspector_specialization : std::false_type
440- {
441- };
442- template <typename T>
443- struct has_inspector_specialization <T, std::void_t <
444- decltype (inspector<T>::inspect(
445- std::declval<inspect_context &>(),
446- std::declval<const T &>()))>>
447- : std::true_type
448- {
449- };
450- template <typename T>
451- inline constexpr bool has_inspector_v =
452- has_inspector_specialization<std::remove_cvref_t <T>>::value;
453-
454- // field_map detection
455- template <typename T, typename = void >
456- struct has_field_map : std::false_type
457- {
458- };
459- template <typename T>
460- struct has_field_map <T, std::void_t <decltype (field_map<T>::fields())>>
461- : std::true_type
462- {
463- };
464- template <typename T>
465- inline constexpr bool has_field_map_v =
466- has_field_map<std::remove_cvref_t <T>>::value;
467-
468- #if VIX_HAS_EXPECTED
469- template <typename T>
470- struct is_expected : std::false_type
471- {
472- };
473- template <typename T, typename E>
474- struct is_expected <std::expected<T, E>> : std::true_type
475- {
476- };
477- template <typename T>
478- inline constexpr bool is_expected_v = is_expected<std::remove_cvref_t <T>>::value;
479- #endif
480-
481- } // namespace traits
482-
483- namespace concepts
484- {
485-
486- template <typename T>
487- concept Ostreamable = traits::is_ostreamable_v<T>;
488- template <typename T>
489- concept StringLike = traits::is_string_like_v<T>;
490- template <typename T>
491- concept Range = traits::is_range_v<T>;
492- template <typename T>
493- concept MapLike = traits::is_map_like_v<T>;
494- template <typename T>
495- concept TupleLike = traits::is_tuple_like_v<T> && !Range<T>;
496- template <typename T>
497- concept HasVixInspect = traits::has_vix_inspect_hook_v<T>;
498- template <typename T>
499- concept HasInspector = traits::has_inspector_v<T>;
500- template <typename T>
501- concept HasFieldMap = traits::has_field_map_v<T>;
502- template <typename T>
503- concept Duration = traits::is_duration_v<T>;
504- template <typename T>
505- concept TimePoint = traits::is_time_point_v<T>;
506-
507- } // namespace concepts
508-
509170 /* *
510171 * @brief Complete set of compile-time and runtime metadata for a type T.
511172 *
@@ -2083,10 +1744,10 @@ namespace vix
20831744 * @brief Inspect a value mid-expression and return it unchanged.
20841745 *
20851746 * @example
2086- * auto result = vix::tap (compute()); // prints and returns
1747+ * auto result = vix::inspect_tap (compute()); // prints and returns
20871748 */
20881749 template <typename T>
2089- const T &tap (const T &value, std::string_view label = " " )
1750+ const T &inspect_tap (const T &value, std::string_view label = " " )
20901751 {
20911752 auto &os = *default_options ().out ;
20921753 if (!label.empty ())
0 commit comments