timemory  3.2.1
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
concepts.hpp
Go to the documentation of this file.
1 // MIT License
2 //
3 // Copyright (c) 2020, The Regents of the University of California,
4 // through Lawrence Berkeley National Laboratory (subject to receipt of any
5 // required approvals from the U.S. Dept. of Energy). All rights reserved.
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a copy
8 // of this software and associated documentation files (the "Software"), to deal
9 // in the Software without restriction, including without limitation the rights
10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 // copies of the Software, and to permit persons to whom the Software is
12 // furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in all
15 // copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 // SOFTWARE.
24 
25 #pragma once
26 
27 #include <cstddef>
28 #include <cstdint>
29 #include <string>
30 #include <tuple>
31 #include <type_traits>
32 
33 #if __cplusplus >= 201703L // C++17
34 # include <string_view>
35 #endif
36 
37 //--------------------------------------------------------------------------------------//
38 
39 #define TIMEMORY_IMPL_IS_CONCEPT(CONCEPT) \
40  struct CONCEPT \
41  {}; \
42  template <typename Tp> \
43  struct is_##CONCEPT \
44  { \
45  private: \
46  template <typename, typename = std::true_type> \
47  struct have : std::false_type \
48  {}; \
49  template <typename U> \
50  struct have<U, typename std::is_base_of<typename U::CONCEPT, U>::type> \
51  : std::true_type \
52  {}; \
53  template <typename U> \
54  struct have<U, typename std::is_base_of<typename U::CONCEPT##_type, U>::type> \
55  : std::true_type \
56  {}; \
57  \
58  public: \
59  using type = typename is_##CONCEPT::template have< \
60  typename std::remove_cv<Tp>::type>::type; \
61  static constexpr bool value = \
62  is_##CONCEPT::template have<typename std::remove_cv<Tp>::type>::value; \
63  };
64 // constexpr operator bool() const noexcept { return value; }
65 
66 //--------------------------------------------------------------------------------------//
67 namespace tim
68 {
69 namespace cereal
70 {
71 namespace detail
72 {
73 //
74 class OutputArchiveBase;
75 class InputArchiveBase;
76 //
77 } // namespace detail
78 } // namespace cereal
79 } // namespace tim
80 //
81 namespace tim
82 {
83 //
84 using true_type = std::true_type;
85 using false_type = std::false_type;
86 //
87 struct null_type;
88 //
89 struct quirk_type;
90 //
91 namespace audit
92 {
93 struct incoming;
94 struct outgoing;
95 } // namespace audit
96 //
97 namespace trait
98 {
99 template <typename Tp>
100 struct is_available;
101 //
102 template <typename Tp>
103 struct is_component;
104 } // namespace trait
105 //
106 namespace
107 {
108 template <typename Tp>
109 struct anonymous
110 {
111  using type = Tp;
112 };
113 //
114 template <typename Tp>
115 using anonymous_t = typename anonymous<Tp>::type;
116 } // namespace
117 //
118 namespace component
119 {
120 template <size_t Idx, typename Tag>
121 struct user_bundle;
122 //
123 template <size_t Nt, typename ComponentsT, typename DifferentiatorT = anonymous_t<void>>
124 struct gotcha;
125 //
126 template <typename... Types>
127 struct placeholder;
128 //
129 struct nothing;
130 //
131 } // namespace component
132 //
133 template <typename... Types>
134 class lightweight_tuple;
135 //
136 namespace concepts
137 {
138 //
139 using input_archive_base = cereal::detail::InputArchiveBase;
140 using output_archive_base = cereal::detail::OutputArchiveBase;
141 //
142 //--------------------------------------------------------------------------------------//
143 /// \struct tim::concepts::is_empty
144 /// \brief concept that specifies that a variadic type is empty
145 ///
147 
148 template <template <typename...> class Tuple>
149 struct is_empty<Tuple<>> : true_type
150 {};
151 
152 //--------------------------------------------------------------------------------------//
153 /// \struct tim::concepts::is_null_type
154 /// \brief concept that specifies that a type is not a useful type
155 ///
157 
158 template <template <typename...> class Tuple>
159 struct is_null_type<Tuple<>> : true_type
160 {};
161 
162 template <>
163 struct is_null_type<void> : true_type
164 {};
165 
166 template <>
167 struct is_null_type<false_type> : true_type
168 {};
169 
170 template <>
171 struct is_null_type<::tim::null_type> : true_type
172 {};
173 
174 //--------------------------------------------------------------------------------------//
175 /// \struct tim::concepts::is_placeholder
176 /// \brief concept that specifies that a type is not necessarily marked as not available
177 /// but is still a dummy type
178 ///
180 
181 template <typename... Types>
182 struct is_placeholder<component::placeholder<Types...>> : true_type
183 {};
184 
185 template <>
186 struct is_placeholder<component::placeholder<component::nothing>> : true_type
187 {};
188 
189 template <>
190 struct is_placeholder<component::nothing> : true_type
191 {};
192 
193 //--------------------------------------------------------------------------------------//
194 /// \struct tim::concepts::is_component
195 /// \brief concept that specifies that a type is a component. Components are used to
196 /// perform some measurement, capability, or logging implementation. Adding this
197 /// concept can be performs through inheriting from \ref tim::component::base,
198 /// inheriting from tim::concepts::component, or specializing either \ref
199 /// tim::concepts::is_component or \ref tim::trait::is_component (with the latter
200 /// being deprecated).
201 ///
202 struct component
203 {};
204 //
205 template <typename Tp>
207 {
208 private:
209  /// did not inherit
210  template <typename, typename = std::true_type>
211  struct have : std::false_type
212  {};
213 
214  /// did inherit
215  template <typename U>
216  struct have<U, typename std::is_base_of<typename U::component, U>::type>
217  : std::true_type
218  {};
219 
220  /// this uses sfinae to see if U::is_component is provided within the type
221  template <typename U>
222  static constexpr decltype(U::is_component, bool{}) test(int)
223  {
224  return U::is_component;
225  }
226 
227  /// this checks for the (deprecated) `tim::trait::is_component` specialization
228  /// and checks for inheritance
229  template <typename Up>
230  static constexpr bool test(long)
231  {
233  is_component::template have<std::remove_cv_t<Tp>>::value;
234  }
235 
236 public:
237  static constexpr bool value = test<Tp>(int{});
238  using type = std::conditional_t<value, true_type, false_type>;
239 };
240 
241 //--------------------------------------------------------------------------------------//
242 /// \struct tim::concepts::is_quirk_type
243 /// \brief concept that specifies that a type is a quirk. Quirks are used to modify
244 /// the traditional behavior of component bundles slightly. E.g. disable calling
245 /// start in the constructor of an auto_tuple.
246 ///
248 
249 //--------------------------------------------------------------------------------------//
250 /// \struct tim::concepts::is_api
251 /// \brief concept that specifies that a type is an API. APIs are used to designate
252 /// different project implementations, different external library tools, etc.
253 ///
255 
256 //--------------------------------------------------------------------------------------//
257 /// \struct tim::concepts::is_variadic
258 /// \brief concept that specifies that a type is a generic variadic wrapper
259 ///
261 
262 //--------------------------------------------------------------------------------------//
263 /// \struct tim::concepts::is_wrapper
264 /// \brief concept that specifies that a type is a timemory variadic wrapper
265 ///
267 
268 //--------------------------------------------------------------------------------------//
269 /// \struct tim::concepts::is_stack_wrapper
270 /// \brief concept that specifies that a type is a timemory variadic wrapper
271 /// and components are stack-allocated
272 ///
274 
275 //--------------------------------------------------------------------------------------//
276 /// \struct tim::concepts::is_heap_wrapper
277 /// \brief concept that specifies that a type is a timemory variadic wrapper
278 /// and components are heap-allocated
279 ///
281 
282 //--------------------------------------------------------------------------------------//
283 /// \struct tim::concepts::is_mixed_wrapper
284 /// \brief concept that specifies that a type is a timemory variadic wrapper
285 /// and variadic types are mix of stack- and heap- allocated
286 ///
288 
289 //--------------------------------------------------------------------------------------//
290 /// \struct tim::concepts::is_tagged
291 /// \brief concept that specifies that a type's template parameters include
292 /// a API specific tag as one of the template parameters (usually first)
293 ///
295 
296 //--------------------------------------------------------------------------------------//
297 /// \struct tim::concepts::is_comp_wrapper
298 /// \brief concept that specifies that a type is a timemory variadic wrapper
299 /// that does not perform auto start/stop, e.g. component_{tuple,list,hybrid}
300 ///
302 
303 //--------------------------------------------------------------------------------------//
304 /// \struct tim::concepts::is_auto_wrapper
305 /// \brief concept that specifies that a type is a timemory variadic wrapper
306 /// that performs auto start/stop, e.g. auto_{tuple,list,hybrid}
307 ///
309 
310 //--------------------------------------------------------------------------------------//
311 /// \struct tim::concepts::is_runtime_configurable
312 /// \brief concept that specifies that a type is used to modify behavior at runtime.
313 /// For example, the \ref tim::component::user_bundle component is runtime configurable bc
314 /// it allows you insert components at runtime. The timing category
315 /// (`tim::category::timing`) is another example of a type that is runtime configurable --
316 /// setting `tim::trait::runtime_enabled<tim::category::timing>::set(false);` will disable
317 /// (at runtime) all the types which are part of the timing API. It should be noted that
318 /// types which satisfy `is_runtime_configurable<Tp>::value == true` (e.g. \ref
319 /// tim::component::user_bundle) are not eligible to be inserted into other runtime
320 /// configurable components; i.e. you cannot insert/add \ref
321 /// tim::component::user_trace_bundle into \ref tim::component::user_global_bundle, etc.
322 /// This restriction is primarily due to the significant increase in compile-time that
323 /// arises from allowing this behavior.
324 ///
326 
327 //--------------------------------------------------------------------------------------//
328 /// \struct tim::concepts::is_external_function_wrapper
329 /// \brief concept that specifies that a component type wraps external functions
330 ///
332 
333 //--------------------------------------------------------------------------------------//
334 /// \struct tim::concepts::is_phase_id
335 /// \brief concept that specifies that a type is used for identifying a phase in some
336 /// measurement. For example, `tim::audit::incoming` and `tim::audit::outgoing`
337 /// can be added to overloads to distinguish whether the `double` type in `double
338 /// exp(double val)` is `val` or whether it is the return value.
339 ///
340 /// \code{.cpp}
341 /// struct exp_wrapper_A
342 /// {
343 /// // unable to distingush whether "val" is input or output
344 /// void audit(double val) { ... }
345 /// };
346 ///
347 /// struct exp_wrapper_B
348 /// {
349 /// // able to distingush whether "val" is input or output
350 /// void audit(audit::incoming, double val) { ... }
351 /// void audit(audit::outgoing, double val) { ... }
352 /// };
353 /// \endcode
355 
356 //--------------------------------------------------------------------------------------//
357 /// \struct tim::concepts::is_string_type
358 /// \brief concept that specifies that a component type wraps external functions
359 ///
361 
362 template <>
363 struct is_string_type<std::string> : true_type
364 {};
365 
366 template <>
367 struct is_string_type<char*> : true_type
368 {};
369 
370 template <>
371 struct is_string_type<const char*> : true_type
372 {};
373 
374 #if __cplusplus >= 201703L // C++17
375 template <>
376 struct is_string_type<std::string_view> : true_type
377 {};
378 #endif
379 
380 //--------------------------------------------------------------------------------------//
381 /// \struct tim::concepts::has_gotcha
382 /// \brief determines if a variadic wrapper contains a gotcha component
383 ///
384 template <typename T>
385 struct has_gotcha : std::false_type
386 {};
387 
388 //--------------------------------------------------------------------------------------//
389 /// \struct tim::concepts::has_user_bundle
390 /// \brief concept that specifies that a type is a user_bundle type
391 ///
392 template <typename T>
393 struct has_user_bundle : false_type
394 {};
395 
396 //--------------------------------------------------------------------------------------//
397 /// \struct tim::concepts::is_output_archive
398 /// \brief concept that specifies that a type is an output serialization archive
399 ///
400 template <typename Tp>
402 {
403 private:
404  /// did not inherit
405  template <typename, typename = std::true_type>
406  struct have : std::false_type
407  {};
408 
409  /// did inherit
410  template <typename U>
411  struct have<U, typename std::is_base_of<output_archive_base, U>::type>
412  : std::true_type
413  {};
414 
415 public:
416  static constexpr bool value =
417  is_output_archive::template have<std::remove_cv_t<Tp>>::value;
418  using type = std::conditional_t<value, true_type, false_type>;
419 };
420 
421 //--------------------------------------------------------------------------------------//
422 /// \struct tim::concepts::is_input_archive
423 /// \brief concept that specifies that a type is an input serialization archive
424 ///
425 template <typename Tp>
427 {
428 private:
429  /// did not inherit
430  template <typename, typename = std::true_type>
431  struct have : std::false_type
432  {};
433 
434  /// did inherit
435  template <typename U>
436  struct have<U, typename std::is_base_of<input_archive_base, U>::type> : std::true_type
437  {};
438 
439 public:
440  static constexpr bool value =
441  is_input_archive::template have<std::remove_cv_t<Tp>>::value;
442  using type = std::conditional_t<value, true_type, false_type>;
443 };
444 
445 //--------------------------------------------------------------------------------------//
446 /// \struct tim::concepts::is_archive
447 /// \brief concept that specifies that a type is a serialization archive (input or output)
448 ///
449 template <typename Tp>
451 {
452  static constexpr bool value =
454  using type = std::conditional_t<value, true_type, false_type>;
455 };
456 
457 //--------------------------------------------------------------------------------------//
458 /// \struct tim::concepts::is_acceptable_conversion
459 /// \tparam Lhs the provided type
460 /// \tparam Rhs the target type
461 ///
462 /// \brief This concept designates that is safe to perform a `static_cast<Lhs>(rhs)`
463 /// where needed. This is primarily used in the \ref tim::component::data_tracker
464 /// where `data_tracker<unsigned int, ...>` might be provided another integral type,
465 /// such as `int`.
466 ///
467 template <typename Lhs, typename Rhs>
469 {
470  static constexpr bool value =
471  (std::is_same<Lhs, Rhs>::value ||
472  (std::is_integral<Lhs>::value && std::is_integral<Rhs>::value) ||
473  (std::is_floating_point<Lhs>::value && std::is_floating_point<Rhs>::value));
474 };
475 
476 //--------------------------------------------------------------------------------------//
477 /// \struct tim::concepts::tuple_type
478 /// \brief This concept is used to express how to convert a given type into a
479 /// `std::tuple`, e.g. `tim::component_tuple<T...>` to `std::tuple<T...>`. It
480 /// is necessary for types like \ref tim::component_bundle where certain template
481 /// parameters are tags.
482 ///
483 template <typename T>
485 {
486  using type = typename T::tuple_type;
487 };
488 
489 /// \struct tim::concepts::auto_type
490 /// \brief This concept is used to express how to convert a component bundler into
491 /// another component bundler which performs automatic starting upon construction.
492 ///
493 template <typename T>
494 struct auto_type
495 {
496  using type = typename T::auto_type;
497 };
498 
499 /// \struct tim::concepts::component_type
500 /// \brief This concept is used to express how to convert a component bundler which
501 /// automatically starts upon construction into a type that requires an explicit
502 /// call to start.
503 ///
504 template <typename T>
506 {
507  using type = typename T::component_type;
508 };
509 
510 template <>
511 struct component_type<std::tuple<>>
512 {
513  using type = lightweight_tuple<>;
514 };
515 
516 //--------------------------------------------------------------------------------------//
517 
518 } // namespace concepts
519 
520 template <typename T>
522 
523 template <typename T>
525 
526 template <typename T>
528 
529 template <typename T>
531 
532 template <typename T>
534 
535 //--------------------------------------------------------------------------------------//
536 
537 } // namespace tim
538 
539 //======================================================================================//
540 
541 #if !defined(TIMEMORY_CONCEPT_ALIAS)
542 # define TIMEMORY_CONCEPT_ALIAS(ALIAS, TYPE) \
543  namespace tim \
544  { \
545  namespace concepts \
546  { \
547  template <typename T> \
548  using ALIAS = typename TYPE<T>::type; \
549  } \
550  }
551 #endif
552 
553 //--------------------------------------------------------------------------------------//
554 
560 
564 
565 //--------------------------------------------------------------------------------------//
566 
567 #define TIMEMORY_DEFINE_CONCRETE_CONCEPT(CONCEPT, SPECIALIZED_TYPE, VALUE) \
568  namespace tim \
569  { \
570  namespace concepts \
571  { \
572  template <> \
573  struct CONCEPT<SPECIALIZED_TYPE> : VALUE \
574  {}; \
575  } \
576  }
577 
578 //--------------------------------------------------------------------------------------//
579 
580 #define TIMEMORY_DEFINE_TEMPLATE_CONCEPT(CONCEPT, SPECIALIZED_TYPE, VALUE, TYPE) \
581  namespace tim \
582  { \
583  namespace concepts \
584  { \
585  template <TYPE T> \
586  struct CONCEPT<SPECIALIZED_TYPE<T>> : VALUE \
587  {}; \
588  } \
589  }
590 
591 //--------------------------------------------------------------------------------------//
592 
593 #define TIMEMORY_DEFINE_VARIADIC_CONCEPT(CONCEPT, SPECIALIZED_TYPE, VALUE, TYPE) \
594  namespace tim \
595  { \
596  namespace concepts \
597  { \
598  template <TYPE... T> \
599  struct CONCEPT<SPECIALIZED_TYPE<T...>> : VALUE \
600  {}; \
601  } \
602  }
603 
604 //--------------------------------------------------------------------------------------//
605 
606 #define TIMEMORY_DEFINE_CONCRETE_CONCEPT_TYPE(CONCEPT, SPECIALIZED_TYPE, ...) \
607  namespace tim \
608  { \
609  namespace concepts \
610  { \
611  template <> \
612  struct CONCEPT<SPECIALIZED_TYPE> \
613  { \
614  using type = __VA_ARGS__; \
615  }; \
616  } \
617  }
618 
619 //--------------------------------------------------------------------------------------//
620 
621 #define TIMEMORY_DEFINE_TEMPLATE_CONCEPT_TYPE(CONCEPT, SPECIALIZED_TYPE, TYPE, ...) \
622  namespace tim \
623  { \
624  namespace concepts \
625  { \
626  template <TYPE T> \
627  struct CONCEPT<SPECIALIZED_TYPE<T>> \
628  { \
629  using type = __VA_ARGS__; \
630  }; \
631  } \
632  }
633 
634 //--------------------------------------------------------------------------------------//
635 
636 #define TIMEMORY_DEFINE_VARIADIC_CONCEPT_TYPE(CONCEPT, SPECIALIZED_TYPE, TYPE, ...) \
637  namespace tim \
638  { \
639  namespace concepts \
640  { \
641  template <TYPE... T> \
642  struct CONCEPT<SPECIALIZED_TYPE<T...>> \
643  { \
644  using type = __VA_ARGS__; \
645  }; \
646  } \
647  }
This is a variadic component wrapper which provides the least amount of runtime and compilation overh...
#define TIMEMORY_CONCEPT_ALIAS(ALIAS, TYPE)
Definition: concepts.hpp:542
#define TIMEMORY_IMPL_IS_CONCEPT(CONCEPT)
Definition: concepts.hpp:39
typename is_stack_wrapper< T >::type is_stack_wrapper_t
Definition: concepts.hpp:558
typename is_variadic< T >::type is_variadic_t
Definition: concepts.hpp:556
typename T::tuple_type type
Definition: concepts.hpp:486
typename auto_type< T >::type auto_type_t
Definition: concepts.hpp:562
cereal::detail::InputArchiveBase input_archive_base
Definition: concepts.hpp:139
typename tuple_type< T >::type tuple_type_t
Definition: concepts.hpp:561
cereal::detail::OutputArchiveBase output_archive_base
Definition: concepts.hpp:140
typename is_heap_wrapper< T >::type is_heap_wrapper_t
Definition: concepts.hpp:559
typename is_empty< T >::type is_empty_t
Definition: concepts.hpp:555
typename T::component_type type
Definition: concepts.hpp:507
typename is_wrapper< T >::type is_wrapper_t
Definition: concepts.hpp:557
typename T::auto_type type
Definition: concepts.hpp:496
typename component_type< T >::type component_type_t
Definition: concepts.hpp:563
This concept is used to express how to convert a component bundler into another component bundler whi...
Definition: concepts.hpp:495
This concept is used to express how to convert a given type into a std::tuple, e.g....
Definition: concepts.hpp:485
This concept is used to express how to convert a component bundler which automatically starts upon co...
Definition: concepts.hpp:506
void audit(TupleT< Tp... > &obj, Args &&... args)
Definition: functional.cpp:921
Definition: kokkosp.cpp:38
typename concepts::is_heap_wrapper< T >::type is_heap_wrapper_t
Definition: concepts.hpp:533
typename concepts::is_empty< T >::type is_empty_t
Definition: concepts.hpp:521
typename concepts::is_stack_wrapper< T >::type is_stack_wrapper_t
Definition: concepts.hpp:530
typename concepts::is_wrapper< T >::type is_wrapper_t
Definition: concepts.hpp:527
typename concepts::is_variadic< T >::type is_variadic_t
Definition: concepts.hpp:524
Used by component audit member function to designate the parameters being passed are incoming (e....
Definition: types.hpp:780
Used by component audit member function to designate the parameters being passed are outgoing (e....
Definition: types.hpp:790
determines if a variadic wrapper contains a gotcha component
Definition: concepts.hpp:386
concept that specifies that a type is a user_bundle type
Definition: concepts.hpp:394
This concept designates that is safe to perform a static_cast<Lhs>(rhs) where needed....
Definition: concepts.hpp:469
concept that specifies that a type is a serialization archive (input or output)
Definition: concepts.hpp:451
std::conditional_t< value, true_type, false_type > type
Definition: concepts.hpp:454
static constexpr bool value
Definition: concepts.hpp:452
concept that specifies that a type is a component. Components are used to perform some measurement,...
Definition: concepts.hpp:207
std::conditional_t< value, true_type, false_type > type
Definition: concepts.hpp:238
static constexpr bool value
Definition: concepts.hpp:237
concept that specifies that a variadic type is empty
Definition: concepts.hpp:146
typename is_empty ::template have< typename std::remove_cv< Tp >::type >::type type
Definition: concepts.hpp:146
concept that specifies that a type is a timemory variadic wrapper and components are heap-allocated
Definition: concepts.hpp:280
typename is_heap_wrapper ::template have< typename std::remove_cv< Tp >::type >::type type
Definition: concepts.hpp:280
concept that specifies that a type is an input serialization archive
Definition: concepts.hpp:427
std::conditional_t< value, true_type, false_type > type
Definition: concepts.hpp:442
static constexpr bool value
Definition: concepts.hpp:440
concept that specifies that a type is not a useful type
Definition: concepts.hpp:156
concept that specifies that a type is an output serialization archive
Definition: concepts.hpp:402
std::conditional_t< value, true_type, false_type > type
Definition: concepts.hpp:418
static constexpr bool value
Definition: concepts.hpp:416
concept that specifies that a type is not necessarily marked as not available but is still a dummy ty...
Definition: concepts.hpp:179
concept that specifies that a type is a timemory variadic wrapper and components are stack-allocated
Definition: concepts.hpp:273
typename is_stack_wrapper ::template have< typename std::remove_cv< Tp >::type >::type type
Definition: concepts.hpp:273
concept that specifies that a component type wraps external functions
Definition: concepts.hpp:360
concept that specifies that a type is a generic variadic wrapper
Definition: concepts.hpp:260
typename is_variadic ::template have< typename std::remove_cv< Tp >::type >::type type
Definition: concepts.hpp:260
concept that specifies that a type is a timemory variadic wrapper
Definition: concepts.hpp:266
typename is_wrapper ::template have< typename std::remove_cv< Tp >::type >::type type
Definition: concepts.hpp:266
this is a placeholder type for optional type-traits. It is used as the default type for the type-trai...
Definition: types.hpp:225
trait that designates the type is a timemory component
typename typename typename
Definition: types.hpp:226