TypeTraits.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines type traits, some of which are future STL type_traits header
6 ///
7 /// Features present in C++17 are in the "cpp17" namespace.
8 
9 #pragma once
10 
11 #include <array>
12 #include <complex>
13 #include <cstddef>
14 #include <deque>
15 #include <forward_list>
16 #include <functional> // for reference_wrapper
17 #include <future>
18 #include <list>
19 #include <map>
20 #include <memory>
21 #include <ostream>
22 #include <queue>
23 #include <set>
24 #include <stack>
25 #include <type_traits>
26 #include <unordered_map>
27 #include <unordered_set>
28 #include <vector>
29 
30 #include "Utilities/NoSuchType.hpp"
31 #include "Utilities/Requires.hpp"
33 #include "Utilities/TMPL.hpp"
34 
35 /// \ingroup TypeTraitsGroup
36 /// C++ STL code present in C++17
37 namespace cpp17 {
38 
39 /*!
40  * \ingroup UtilitiesGroup
41  * \brief Mark a return type as being "void". In C++17 void is a regular type
42  * under certain circumstances, so this can be replaced by `void` then.
43  *
44  * The proposal is available
45  * [here](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0146r1.html)
46  */
47 struct void_type {};
48 
49 /// \ingroup TypeTraitsGroup
50 /// \brief A compile-time boolean
51 ///
52 /// \usage
53 /// For any bool `B`
54 /// \code
55 /// using result = cpp17::bool_constant<B>;
56 /// \endcode
57 ///
58 /// \see std::bool_constant std::integral_constant std::true_type
59 /// std::false_type
60 template <bool B>
62 
63 // @{
64 /// \ingroup TypeTraitsGroup
65 /// \brief A logical AND on the template parameters
66 ///
67 /// \details
68 /// Given a list of ::bool_constant template parameters computes their
69 /// logical AND. If the result is `true` then derive off of std::true_type,
70 /// otherwise derive from std::false_type. See the documentation for
71 /// std::conjunction for more details.
72 ///
73 /// \usage
74 /// For any set of types `Ti` that are ::bool_constant like
75 /// \code
76 /// using result = cpp17::conjunction<T0, T1, T2>;
77 /// \endcode
78 /// \pre For all types `Ti`, `Ti::value` is a `bool`
79 ///
80 /// \metareturns
81 /// ::bool_constant
82 ///
83 /// \semantics
84 /// If `T::value != false` for all `Ti`, then
85 /// \code
86 /// using result = cpp17::bool_constant<true>;
87 /// \endcode
88 /// otherwise
89 /// \code
90 /// using result = cpp17::bool_constant<false>;
91 /// \endcode
92 ///
93 /// \example
94 /// \snippet Utilities/Test_TypeTraits.cpp conjunction_example
95 /// \see std::conjunction, disjunction, std::disjunction
96 template <class...>
98 /// \cond HIDDEN_SYMBOLS
99 template <class B1>
100 struct conjunction<B1> : B1 {};
101 template <class B1, class... Bn>
102 struct conjunction<B1, Bn...>
103  : std::conditional_t<static_cast<bool>(B1::value), conjunction<Bn...>, B1> {
104 };
105 /// \endcond
106 /// \see std::conjunction
107 template <class... B>
108 constexpr bool conjunction_v = conjunction<B...>::value;
109 // @}
110 
111 // @{
112 /// \ingroup TypeTraitsGroup
113 /// \brief A logical OR on the template parameters
114 ///
115 /// \details
116 /// Given a list of ::bool_constant template parameters computes their
117 /// logical OR. If the result is `true` then derive off of std::true_type,
118 /// otherwise derive from std::false_type. See the documentation for
119 /// std::conjunction for more details.
120 ///
121 /// \usage
122 /// For any set of types `Ti` that are ::bool_constant like
123 /// \code
124 /// using result = cpp17::disjunction<T0, T1, T2>;
125 /// \endcode
126 /// \pre For all types `Ti`, `Ti::value` is a `bool`
127 ///
128 /// \metareturns
129 /// ::bool_constant
130 ///
131 /// \semantics
132 /// If `T::value == true` for any `Ti`, then
133 /// \code
134 /// using result = cpp17::bool_constant<true>;
135 /// \endcode
136 /// otherwise
137 /// \code
138 /// using result = cpp17::bool_constant<false>;
139 /// \endcode
140 ///
141 /// \example
142 /// \snippet Utilities/Test_TypeTraits.cpp disjunction_example
143 /// \see std::disjunction, conjunction, std::conjunction
144 template <class...>
146 /// \cond HIDDEN_SYMBOLS
147 template <class B1>
148 struct disjunction<B1> : B1 {};
149 template <class B1, class... Bn>
150 struct disjunction<B1, Bn...>
151  : std::conditional_t<static_cast<bool>(B1::value), B1, disjunction<Bn...>> {
152 };
153 /// \endcond
154 /// \see std::disjunction
155 template <class... B>
156 constexpr bool disjunction_v = disjunction<B...>::value;
157 // @}
158 
159 /// \ingroup TypeTraitsGroup
160 /// \brief Negate a ::bool_constant
161 ///
162 /// \details
163 /// Given a ::bool_constant returns the logical NOT of it.
164 ///
165 /// \usage
166 /// For a ::bool_constant `B`
167 /// \code
168 /// using result = cpp17::negate<B>;
169 /// \endcode
170 ///
171 /// \metareturns
172 /// ::bool_constant
173 ///
174 /// \semantics
175 /// If `B::value == true` then
176 /// \code
177 /// using result = cpp17::bool_constant<false>;
178 /// \endcode
179 ///
180 /// \example
181 /// \snippet Utilities/Test_TypeTraits.cpp negation_example
182 /// \see std::negation
183 /// \tparam B the ::bool_constant to negate
184 template <class B>
185 struct negation : bool_constant<!B::value> {};
186 
187 /// \ingroup TypeTraitsGroup
188 /// \brief Given a set of types, returns `void`
189 ///
190 /// \details
191 /// Given a list of types, returns `void`. This is very useful for controlling
192 /// name lookup resolution via partial template specialization.
193 ///
194 /// \usage
195 /// For any set of types `Ti`,
196 /// \code
197 /// using result = cpp17::void_t<T0, T1, T2, T3>;
198 /// \endcode
199 ///
200 /// \metareturns
201 /// void
202 ///
203 /// \semantics
204 /// For any set of types `Ti`,
205 /// \code
206 /// using result = void;
207 /// \endcode
208 ///
209 /// \example
210 /// \snippet Utilities/Test_TypeTraits.cpp void_t_example
211 /// \see std::void_t
212 /// \tparam Ts the set of types
213 template <typename... Ts>
214 using void_t = void;
215 
216 /*!
217  * \ingroup TypeTraitsGroup
218  * \brief Variable template for is_same
219  */
220 template <typename T, typename U>
222 
223 /// \ingroup TypeTraitsGroup
224 template <typename T>
225 constexpr bool is_lvalue_reference_v = std::is_lvalue_reference<T>::value;
226 
227 /// \ingroup TypeTraitsGroup
228 template <typename T>
229 constexpr bool is_rvalue_reference_v = std::is_rvalue_reference<T>::value;
230 
231 /// \ingroup TypeTraitsGroup
232 template <typename T>
233 constexpr bool is_reference_v = std::is_reference<T>::value;
234 
235 /// \ingroup TypeTraitsGroup
236 template <class T, class... Args>
237 using is_constructible_t = typename std::is_constructible<T, Args...>::type;
238 
239 /// \ingroup TypeTraitsGroup
240 template <class T, class... Args>
241 constexpr bool is_constructible_v = std::is_constructible<T, Args...>::value;
242 
243 /// \ingroup TypeTraitsGroup
244 template <class T, class... Args>
245 constexpr bool is_trivially_constructible_v =
246  std::is_trivially_constructible<T, Args...>::value;
247 
248 /// \ingroup TypeTraitsGroup
249 template <class T, class... Args>
250 constexpr bool is_nothrow_constructible_v =
251  std::is_nothrow_constructible<T, Args...>::value;
252 
253 /// \ingroup TypeTraitsGroup
254 template <class T>
255 constexpr bool is_default_constructible_v =
257 
258 /// \ingroup TypeTraitsGroup
259 template <class T>
260 constexpr bool is_trivially_default_constructible_v =
262 
263 /// \ingroup TypeTraitsGroup
264 template <class T>
265 constexpr bool is_nothrow_default_constructible_v =
267 
268 /// \ingroup TypeTraitsGroup
269 template <class T>
270 constexpr bool is_copy_constructible_v = std::is_copy_constructible<T>::value;
271 
272 /// \ingroup TypeTraitsGroup
273 template <class T>
274 constexpr bool is_trivially_copy_constructible_v =
276 
277 /// \ingroup TypeTraitsGroup
278 template <class T>
279 constexpr bool is_nothrow_copy_constructible_v =
281 
282 /// \ingroup TypeTraitsGroup
283 template <class T>
284 constexpr bool is_move_constructible_v = std::is_move_constructible<T>::value;
285 
286 /// \ingroup TypeTraitsGroup
287 template <class T>
288 constexpr bool is_trivially_move_constructible_v =
290 
291 /// \ingroup TypeTraitsGroup
292 template <class T>
293 constexpr bool is_nothrow_move_constructible_v =
295 
296 /// \ingroup TypeTraitsGroup
297 template <class T, class U>
298 constexpr bool is_assignable_v = std::is_assignable<T, U>::value;
299 
300 /// \ingroup TypeTraitsGroup
301 template <class T, class U>
302 constexpr bool is_trivially_assignable_v =
304 
305 /// \ingroup TypeTraitsGroup
306 template <class T, class U>
307 constexpr bool is_nothrow_assignable_v =
309 
310 /// \ingroup TypeTraitsGroup
311 template <class From, class To>
312 constexpr bool is_convertible_v = std::is_convertible<From, To>::value;
313 
314 /// \ingroup TypeTraitsGroup
315 template <class T>
316 constexpr bool is_copy_assignable_v = std::is_copy_assignable<T>::value;
317 
318 /// \ingroup TypeTraitsGroup
319 template <class T>
320 constexpr bool is_trivially_copy_assignable_v =
322 
323 /// \ingroup TypeTraitsGroup
324 template <class T>
325 constexpr bool is_nothrow_copy_assignable_v =
327 
328 /// \ingroup TypeTraitsGroup
329 template <class T>
330 constexpr bool is_move_assignable_v = std::is_move_assignable<T>::value;
331 
332 /// \ingroup TypeTraitsGroup
333 template <class T>
334 constexpr bool is_trivially_move_assignable_v =
336 
337 /// \ingroup TypeTraitsGroup
338 template <class T>
339 constexpr bool is_nothrow_move_assignable_v =
341 
342 /// \ingroup TypeTraitsGroup
343 template <class Base, class Derived>
344 constexpr bool is_base_of_v = std::is_base_of<Base, Derived>::value;
345 
346 /// \ingroup TypeTraitsGroup
347 template <class T>
348 constexpr bool is_unsigned_v = std::is_unsigned<T>::value;
349 
350 /// \ingroup TypeTraitsGroup
351 template <class T>
352 constexpr bool is_arithmetic_v = std::is_arithmetic<T>::value;
353 
354 /// \ingroup TypeTraitsGroup
355 template <class T>
356 constexpr bool is_floating_point_v = std::is_floating_point<T>::value;
357 
358 /// \ingroup TypeTraitsGroup
359 template <class T>
360 constexpr bool is_integral_v = std::is_integral<T>::value;
361 
362 /// \ingroup TypeTraitsGroup
363 template <class T>
364 constexpr bool is_fundamental_v = std::is_fundamental<T>::value;
365 
366 } // namespace cpp17
367 
368 /// \ingroup TypeTraitsGroup
369 /// C++ STL code present in C++20
370 namespace cpp20 {
371 /// \ingroup TypeTraits
372 template <class T>
373 struct remove_cvref {
374  // clang-tidy use using instead of typedef
376 };
377 
378 /// \ingroup TypeTraits
379 template <class T>
380 using remove_cvref_t = typename remove_cvref<T>::type;
381 } // namespace cpp20
382 
383 /// \ingroup TypeTraitsGroup
384 /// A collection of useful type traits
385 namespace tt {
386 // @{
387 /*!
388  * \ingroup TypeTraitsGroup
389  * \brief Check if `T` is copy constructible
390  *
391  * The STL `std::is_copy_constructible` does not work as expected with some
392  * types, such as `std::unordered_map`. This is because
393  * `std::is_copy_constructible` only checks that the copy construction call is
394  * well-formed, not that it could actually be done in practice. To get around
395  * this for containers we check that `T::value_type` is also copy constructible.
396  */
397 template <typename T, typename = void>
399 
400 /// \cond
401 template <typename T>
402 struct can_be_copy_constructed<T, cpp17::void_t<typename T::value_type>>
404  cpp17::is_copy_constructible_v<T> and
405  cpp17::is_copy_constructible_v<typename T::value_type>> {};
406 /// \endcond
407 
408 template <typename T>
409 constexpr bool can_be_copy_constructed_v = can_be_copy_constructed<T>::value;
410 // @}
411 
412 // @{
413 /// \ingroup TypeTraitsGroup
414 /// \brief Check if type T is a std::array
415 ///
416 /// \details
417 /// Given a type `T` derives from std::true_type if `T` is a std::array and from
418 /// std::false_type if `T` is not a std::array.
419 ///
420 /// \usage
421 /// For any type `T`
422 /// \code
423 /// using result = tt::is_std_array<T>;
424 /// \endcode
425 ///
426 /// \metareturns
427 /// cpp17::bool_constant
428 ///
429 /// \semantics
430 /// If `T` is a std::array then
431 /// \code
432 /// typename result::type = cpp17::bool_constant<true>;
433 /// \endcode
434 /// otherwise
435 /// \code
436 /// typename result::type = cpp17::bool_constant<false>;
437 /// \endcode
438 ///
439 /// \example
440 /// \snippet Utilities/Test_TypeTraits.cpp is_std_array_example
441 /// \see is_a is_std_array_of_size
442 /// \tparam T the type to check
443 template <typename T>
445 /// \cond HIDDEN_SYMBOLS
446 template <typename T, size_t N>
447 struct is_std_array<std::array<T, N>> : std::true_type {};
448 /// \endcond
449 /// \see is_std_array
450 template <typename T>
452 
453 /// \see is_std_array
454 template <typename T>
456 // @}
457 
458 // @{
459 /// \ingroup TypeTraitsGroup
460 /// \brief Check if type T is a std::array of a given size
461 ///
462 /// \details
463 /// Given a size_t `N` and type `T` derives from std::true_type if `T`
464 /// is a std::array of size `N` and from std::false_type otherwise.
465 ///
466 /// \usage
467 /// For any type `T`
468 /// \code
469 /// using result = tt::is_std_array_of_size<N, T>;
470 /// \endcode
471 ///
472 /// \metareturns
473 /// cpp17::bool_constant
474 ///
475 /// \semantics
476 /// If `T` is a std::array of size `N` then
477 /// \code
478 /// typename result::type = cpp17::bool_constant<true>;
479 /// \endcode
480 /// otherwise
481 /// \code
482 /// typename result::type = cpp17::bool_constant<false>;
483 /// \endcode
484 ///
485 /// \example
486 /// \snippet Utilities/Test_TypeTraits.cpp is_std_array_of_size_example
487 /// \see is_std_array
488 /// \tparam T the type to check
489 template <size_t N, typename T>
491 /// \cond HIDDEN_SYMBOLS
492 template <size_t N, typename T>
493 struct is_std_array_of_size<N, std::array<T, N>> : std::true_type {};
494 /// \endcond
495 /// \see is_std_array_of_size
496 template <size_t N, typename T>
498 
499 /// \see is_std_array_of_size
500 template <size_t N, typename T>
502 // @}
503 
504 // @{
505 /// \ingroup TypeTraitsGroup
506 /// \brief Check if type `T` is a template specialization of `U`
507 ///
508 /// \requires `U` is a class template
509 /// \effects If `T` is a template specialization of `U`, then inherits from
510 /// std::true_type, otherwise inherits from std::false_type
511 ///
512 /// \usage
513 /// For any type `T` and class template `U`
514 /// \code
515 /// using result = tt::is_a<U, T>;
516 /// \endcode
517 /// \metareturns
518 /// cpp17::bool_constant
519 ///
520 /// \semantics
521 /// If the type `T` is a template specialization of the type `U`, then
522 /// \code
523 /// typename result::type = std::true_type;
524 /// \endcode
525 /// otherwise
526 /// \code
527 /// typename result::type = std::false_type;
528 /// \endcode
529 ///
530 /// \example
531 /// \snippet Utilities/Test_TypeTraits.cpp is_a_example
532 /// \see is_std_array
533 /// \tparam T type to check
534 /// \tparam U the type that T might be a template specialization of
535 template <template <typename...> class U, typename T>
536 struct is_a : std::false_type {};
537 /// \cond HIDDEN_SYMBOLS
538 template <template <typename...> class U, typename... Args>
539 struct is_a<U, U<Args...>> : std::true_type {};
540 /// \endcond
541 /// \see is_a
542 template <template <typename...> class U, typename... Args>
543 constexpr bool is_a_v = is_a<U, Args...>::value;
544 
545 /// \see is_a
546 template <template <typename...> class U, typename... Args>
547 using is_a_t = typename is_a<U, Args...>::type;
548 // @}
549 
550 // @{
551 /// \ingroup TypeTraitsGroup
552 /// \brief Check if type T has a begin() and end() function
553 ///
554 /// \details
555 /// Given a type `T` inherits from std::true_type if `T` has member functions
556 /// `begin()` and `end()`, otherwise inherits from std::false_type
557 ///
558 /// \usage
559 /// For any type `T`
560 /// \code
561 /// using result = tt::is_iterable<T>;
562 /// \endcode
563 ///
564 /// \metareturns
565 /// cpp17::bool_constant
566 ///
567 /// \semantics
568 /// If `T` has member function `begin()` and `end()` then
569 /// \code
570 /// typename result::type = std::true_type;
571 /// \endcode
572 /// otherwise
573 /// \code
574 /// typename result::type = std::false_type;
575 /// \endcode
576 ///
577 /// \example
578 /// \snippet Utilities/Test_TypeTraits.cpp is_iterable_example
579 /// \see has_size
580 /// \tparam T the type to check
581 template <typename T, typename = cpp17::void_t<>>
583 /// \cond HIDDEN_SYMBOLS
584 template <typename T>
585 struct is_iterable<T, cpp17::void_t<decltype(std::declval<T>().begin(),
586  std::declval<T>().end())>>
587  : std::true_type {};
588 /// \endcond
589 /// \see is_iterable
590 template <typename T>
592 
593 /// \see is_iterable
594 template <typename T>
596 // @}
597 
598 // @{
599 /// \ingroup TypeTraitsGroup
600 /// \brief Check if type T has <, <=, >, >=, ==, !=
601 ///
602 /// \details
603 /// Given a type `T` inherits from std::true_type if `T` has operators `<`,
604 /// `<=`, `>`, `>=`, `==`, and `!=` defined, otherwise inherits from
605 /// std::false_type.
606 ///
607 /// \usage
608 /// For any type `T`
609 /// \code
610 /// using result = tt::is_comparable<T>;
611 /// \endcode
612 ///
613 /// \metareturns
614 /// cpp17::bool_constant
615 ///
616 /// \semantics
617 /// If `T` has operators `<`, `<=`, `>`, `>=`, `==`, and `!=` defined, then
618 /// \code
619 /// typename result::type = std::true_type;
620 /// \endcode
621 /// otherwise
622 /// \code
623 /// typename result::type = std::false_type;
624 /// \endcode
625 ///
626 /// \example
627 /// \snippet Utilities/Test_TypeTraits.cpp is_comparable_example
628 /// \see has_equivalence has_inequivalence
629 /// \tparam T the type to check
630 template <typename T, typename = cpp17::void_t<>>
632 /// \cond HIDDEN_SYMBOLS
633 template <typename T>
634 struct is_comparable<
635  T, cpp17::void_t<decltype(std::declval<T>() < std::declval<T>()),
636  decltype(std::declval<T>() <= std::declval<T>()),
637  decltype(std::declval<T>() > std::declval<T>()),
638  decltype(std::declval<T>() >= std::declval<T>()),
639  decltype(std::declval<T>() == std::declval<T>()),
640  decltype(std::declval<T>() != std::declval<T>())>>
641  : std::true_type {};
642 /// \endcond
643 /// \see is_comparable
644 template <typename T>
646 
647 /// \see is_comparable
648 template <typename T>
650 // @}
651 
652 namespace TypeTraits_detail {
653 template <typename T, std::size_t N>
655  const std::array<T, N>& /*array*/);
656 } // namespace TypeTraits_detail
657 
658 // @{
659 /// \ingroup TypeTraitsGroup
660 /// \brief Get the size of a std::array as a std::integral_constant
661 ///
662 /// \details
663 /// Given a std::array, `Array`, returns a std::integral_constant that has the
664 /// size of the array as its value
665 ///
666 /// \usage
667 /// For a std::array `T`
668 /// \code
669 /// using result = tt::array_size<T>;
670 /// \endcode
671 ///
672 /// \metareturns
673 /// std::integral_constant<std::size_t>
674 ///
675 /// \semantics
676 /// For a type `T`,
677 /// \code
678 /// using tt::array_size<std::array<T, N>> = std::integral_constant<std::size_t,
679 /// N>;
680 /// \endcode
681 ///
682 /// \example
683 /// \snippet Utilities/Test_TypeTraits.cpp array_size_example
684 /// \tparam Array the whose size should be stored in value of array_size
685 template <typename Array>
686 using array_size =
687  decltype(TypeTraits_detail::array_size_impl(std::declval<const Array&>()));
688 // @}
689 
690 // @{
691 /// \ingroup TypeTraitsGroup
692 /// \brief Check if type `T` has operator== defined.
693 ///
694 /// \details
695 /// Inherits from std::true_type if the type `T` has operator== defined,
696 /// otherwise inherits from std::false_type
697 ///
698 /// \usage
699 /// For any type `T`,
700 /// \code
701 /// using result = tt::has_equivalence<T>;
702 /// \endcode
703 ///
704 /// \metareturns
705 /// cpp17::bool_constant
706 ///
707 /// \semantics
708 /// If the type `T` has operator== defined, then
709 /// \code
710 /// typename result::type = std::true_type;
711 /// \endcode
712 /// otherwise
713 /// \code
714 /// typename result::type = std::false_type;
715 /// \endcode
716 ///
717 /// \example
718 /// \snippet Utilities/Test_TypeTraits.cpp has_equivalence_example
719 /// \see is_comparable has_inequivalence
720 /// \tparam T the type we want to know if it has operator==
721 template <typename T, typename = cpp17::void_t<>>
723 /// \cond HIDDEN_SYMBOLS
724 template <typename T>
725 struct has_equivalence<
726  T, cpp17::void_t<decltype(std::declval<T>() == std::declval<T>())>>
727  : std::true_type {};
728 /// \endcond
729 /// \see has_equivalence
730 template <typename T>
732 
733 /// \see has_equivalence
734 template <typename T>
736 // @}
737 
738 // @{
739 /// \ingroup TypeTraitsGroup
740 /// \brief Check if type `T` has operator!= defined.
741 ///
742 /// \details
743 /// Inherits from std::true_type if the type `T` has operator!= defined,
744 /// otherwise inherits from std::false_type
745 ///
746 /// \usage
747 /// For any type `T`,
748 /// \code
749 /// using result = tt::has_inequivalence<T>;
750 /// \endcode
751 ///
752 /// \metareturns
753 /// cpp17::bool_constant
754 ///
755 /// \semantics
756 /// If the type `T` has operator!= defined, then
757 /// \code
758 /// typename result::type = std::true_type;
759 /// \endcode
760 /// otherwise
761 /// \code
762 /// typename result::type = std::false_type;
763 /// \endcode
764 ///
765 /// \example
766 /// \snippet Utilities/Test_TypeTraits.cpp has_equivalence_example
767 /// \see is_comparable has_equivalence
768 /// \tparam T the type we want to know if it has operator!=
769 template <typename T, typename U = void>
771 /// \cond HIDDEN_SYMBOLS
772 template <typename T>
773 struct has_inequivalence<
774  T, cpp17::void_t<decltype(std::declval<T>() != std::declval<T>())>>
775  : std::true_type {};
776 /// \endcond
777 /// \see has_inequivalence
778 template <typename T>
780 
781 /// \see has_inequivalence
782 template <typename T>
784 // @}
785 
786 // @{
787 /// \ingroup TypeTraitsGroup
788 /// \brief Check if a type `T` is callable, i.e. `T(Args...)` is evaluable.
789 ///
790 /// \details
791 /// Inherits from std::true_type if `TT` has the call operator, operator()
792 /// defined with arguments `TArgs...`, otherwise inherits from std::false_type.
793 ///
794 /// \usage
795 /// For any type `TT` and types `TArgs_i`,
796 /// \code
797 /// using result = tt::is_callable<TT, TArgs_0, TArgs_1, TArgs_2>;
798 /// \endcode
799 ///
800 /// \metareturns
801 /// cpp17::bool_constant
802 ///
803 /// \semantics
804 /// If the type `TT` defines operator() with arguments `TArgs...`, then
805 /// \code
806 /// typename result::type = std::true_type;
807 /// \endcode
808 /// otherwise
809 /// \code
810 /// typename result::type = std::false_type;
811 /// \endcode
812 ///
813 /// \example
814 /// \snippet Utilities/Test_TypeTraits.cpp is_callable_example
815 /// \see std::is_callable
816 /// \tparam TT the class to check
817 /// \tparam TArgs the args passed to operator()
818 template <typename TT, typename... TArgs>
819 class is_callable {
820  // The reason we have private before public here is that we have static member
821  // functions and since this is meant to be a super lightweight helper class
822  // it's better to break convention than increase code size.
823  private:
824  /// \cond
825  // We pass an int here to disambiguate the two possible templates and have the
826  // compiler prefer the first one. If it cannot be used because there's no
827  // call operator, then it uses the second one.
828  template <typename T, typename... Args>
829  static auto test_callable(int) noexcept
830  -> decltype(std::declval<T>()(std::declval<Args>()...), std::true_type());
831 
832  template <typename, typename...>
833  static auto test_callable(...) noexcept -> std::false_type;
834  /// \endcond
835 
836  public:
837  /// `true` if callable, `false` otherwise
838  static constexpr bool value = decltype(test_callable<TT, TArgs...>(0))::value;
839  /// `std::true_type` if callable, `std::false_type` otherwise
841 };
842 /// \see is_callable
843 template <typename T, typename... Args>
844 constexpr bool is_callable_v = is_callable<T, Args...>::value;
845 
846 /// \see is_callable
847 template <typename T, typename... Args>
848 using is_callable_t = typename is_callable<T, Args...>::type;
849 // @}
850 
851 /*!
852  * \ingroup TypeTraitsGroup
853  * \brief Generate a type trait to check if a class has a member function that
854  * can be invoked with arguments of type `TArgs...`
855  *
856  * The usage of the type trait is identical to the usage of the
857  * `tt::is_callable` type trait. The name of the type trait is
858  * `is_METHOD_NAME_callable` and is not placed in
859  * the `tt` namespace. To avoid collisions it is highly recommended that type
860  * traits generated with this macro are generated into `_detail` namespaces.
861  * This will reduce redefinition compilation errors. Note that a variable
862  * template `is_METHOD_NAME_callable_v`, and a `is_METHOD_NAME_callable_t` that
863  * is either `std::true_type` or `std::false_type` is also generated.
864  *
865  * \example
866  * \snippet Utilities/Test_TypeTraits.cpp CREATE_IS_CALLABLE_EXAMPLE
867  *
868  * \see tt::is_callable
869  */
870 #define CREATE_IS_CALLABLE(METHOD_NAME) \
871  template <typename TT, typename... TArgs> \
872  class is_##METHOD_NAME##_callable { \
873  private: \
874  template <typename T, typename... Args> \
875  static auto test_callable(int) noexcept \
876  -> decltype(std::declval<T>().METHOD_NAME(std::declval<Args>()...), \
877  std::true_type()); \
878  template <typename, typename...> \
879  static auto test_callable(...) noexcept -> std::false_type; \
880  \
881  public: \
882  static constexpr bool value = \
883  decltype(test_callable<TT, TArgs...>(0))::value; \
884  using type = std::integral_constant<bool, value>; \
885  }; \
886  template <typename T, typename... Args> \
887  static constexpr const bool is_##METHOD_NAME##_callable_v = \
888  is_##METHOD_NAME##_callable<T, Args...>::value; \
889  template <typename T, typename... Args> \
890  using is_##METHOD_NAME##_callable_t = \
891  typename is_##METHOD_NAME##_callable<T, Args...>::type;
892 
893 // @{
894 /// \ingroup TypeTraitsGroup
895 /// \brief Check if std::hash and std::equal_to are defined for type T
896 ///
897 /// \details
898 /// Inherits from std::true_type if std::hash and std::equal_to are defined for
899 /// the type `T`, otherwise inherits from std::false_type.
900 ///
901 /// \usage
902 /// For any type `T`
903 /// \code
904 /// using result = tt::is_hashable<T>;
905 /// \endcode
906 ///
907 /// \metareturns
908 /// cpp17::bool_constant
909 ///
910 /// \semantics
911 /// If std::hash and std::equal_to are defined for the type `T`, then
912 /// \code
913 /// typename result::type = std::true_type;
914 /// \endcode
915 /// otherwise
916 /// \code
917 /// typename result::type = std::false_type;
918 /// \endcode
919 ///
920 /// \example
921 /// \snippet Utilities/Test_TypeTraits.cpp is_hashable_example
922 /// \see std::hash std::equal_to
923 /// \tparam T type to check
924 template <typename T, typename = cpp17::void_t<>>
926 /// \cond HIDDEN_SYMBOLS
927 template <typename T>
928 struct is_hashable<T,
929  cpp17::void_t<decltype(std::hash<T>{}, std::equal_to<T>{})>>
930  : std::true_type {};
931 /// \endcond
932 /// \see is_hashable
933 template <typename T>
935 
936 /// \see is_hashable
937 template <typename T>
939 // @}
940 
941 // @{
942 /// \ingroup TypeTraitsGroup
943 /// \brief Check if type `T` is like a std::map or std::unordored_map
944 ///
945 /// \details
946 /// Inherits from std::true_type if the type `T` has a type alias `key_type`,
947 /// type alias `mapped_type`, and `operator[](const typename T::key_type&)`
948 /// defined, otherwise inherits from std::false_type
949 ///
950 /// \usage
951 /// For any type `T`,
952 /// \code
953 /// using result = tt::is_maplike<T>;
954 /// \endcode
955 ///
956 /// \metareturns
957 /// cpp17::bool_constant
958 ///
959 /// \semantics
960 /// If the type `T` has a type alias `key_type`,
961 /// type alias `mapped_type`, and `operator[](const typename T::key_type&)`
962 /// defined, then
963 /// \code
964 /// typename result::type = std::true_type;
965 /// \endcode
966 /// otherwise
967 /// \code
968 /// typename result::type = std::false_type;
969 /// \endcode
970 ///
971 /// \example
972 /// \snippet Utilities/Test_TypeTraits.cpp is_maplike_example
973 /// \see std::map std::unordered_map is_a
974 /// \tparam T the type to check
975 template <typename T, typename = cpp17::void_t<>>
977 /// \cond HIDDEN_SYMBOLS
978 template <typename T>
979 struct is_maplike<T,
980  cpp17::void_t<typename T::key_type, typename T::mapped_type,
981  decltype(std::declval<T&>()[std::declval<
982  const typename T::key_type&>()]),
983  Requires<tt::is_iterable_v<T>>>>
984  : std::true_type {};
985 /// \endcond
986 /// \see is_maplike
987 template <typename T>
989 
990 /// \see is_maplike
991 template <typename T>
993 // @}
994 
995 // @{
996 /// \ingroup TypeTraitsGroup
997 /// \brief Check if type `T` has operator<<(`S`, `T`) defined.
998 ///
999 /// \details
1000 /// Inherits from std::true_type if the type `T` has operator<<(`S`, `T`)
1001 /// defined for a stream `S`, otherwise inherits from std::false_type
1002 ///
1003 /// \usage
1004 /// For any type `T` and stream type `S`,
1005 /// \code
1006 /// using result = tt::is_streamable<S, T>;
1007 /// \endcode
1008 ///
1009 /// \metareturns
1010 /// cpp17::bool_constant
1011 ///
1012 /// \semantics
1013 /// If the type `T` has operator<<(`S`, `T`) defined for stream `S`, then
1014 /// \code
1015 /// typename result::type = std::true_type;
1016 /// \endcode
1017 /// otherwise
1018 /// \code
1019 /// typename result::type = std::false_type;
1020 /// \endcode
1021 ///
1022 /// \example
1023 /// \snippet Utilities/Test_TypeTraits.cpp is_streamable_example
1024 /// \see std::cout std::ifstream std::sstream std::ostream
1025 /// \tparam S the stream type, e.g. std::stringstream or std::ostream
1026 /// \tparam T the type we want to know if it has operator<<
1027 template <typename S, typename T, typename = cpp17::void_t<>>
1028 struct is_streamable : std::false_type {};
1029 /// \cond HIDDEN_SYMBOLS
1030 template <typename S, typename T>
1031 struct is_streamable<
1032  S, T, cpp17::void_t<decltype(std::declval<std::add_lvalue_reference_t<S>>()
1033  << std::declval<T>()),
1034  Requires<not std::is_same<S, T>::value>>>
1035  : std::true_type {};
1036 /// \endcond
1037 /// \see is_streamable
1038 template <typename S, typename T>
1039 constexpr bool is_streamable_v = is_streamable<S, T>::value;
1040 
1041 /// \see is_streamable
1042 template <typename S, typename T>
1043 using is_streamable_t = typename is_streamable<S, T>::type;
1044 
1045 // @}
1046 
1047 // @{
1048 /// \ingroup TypeTraitsGroup
1049 /// \brief Check if type `T` is a std::string, or a C-style string
1050 ///
1051 /// \details
1052 /// Inherits from std::true_type if the type `T` has a is a std::string, or
1053 /// a C-style string, otherwise inherits from std::false_type
1054 ///
1055 /// \usage
1056 /// For any type `T`,
1057 /// \code
1058 /// using result = tt::is_string_like<T>;
1059 /// \endcode
1060 ///
1061 /// \metareturns
1062 /// cpp17::bool_constant
1063 ///
1064 /// \semantics
1065 /// If the type `T` is a std::string, or a C-style string, then
1066 /// \code
1067 /// typename result::type = std::true_type;
1068 /// \endcode
1069 /// otherwise
1070 /// \code
1071 /// typename result::type = std::false_type;
1072 /// \endcode
1073 ///
1074 /// \example
1075 /// \snippet Utilities/Test_TypeTraits.cpp is_string_like_example
1076 /// \see std::string std::is_same
1077 /// \tparam T the type to check
1078 template <typename T, typename = std::nullptr_t>
1079 struct is_string_like : std::false_type {};
1080 /// \cond HIDDEN_SYMBOLS
1081 template <typename T>
1082 struct is_string_like<
1083  T,
1084  Requires<std::is_same<std::decay_t<T>, std::string>::value or
1085  std::is_same<std::decay_t<std::remove_pointer_t<std::decay_t<T>>>,
1086  char>::value>> : std::true_type {};
1087 /// \endcond
1088 /// \see is_string_like
1089 template <typename T>
1090 constexpr bool is_string_like_v = is_string_like<T>::value;
1091 
1092 /// \see is_string_like
1093 template <typename T>
1094 using is_string_like_t = typename is_string_like<T>::type;
1095 
1096 // @}
1097 
1098 // @{
1099 /// \ingroup TypeTraitsGroup
1100 /// \brief Check if type `T` has a `get_clone()` member function
1101 ///
1102 /// \details
1103 /// Inherits from std::true_type if the type `T` has a `get_clone()` member
1104 /// function, otherwise inherits from std::false_type
1105 ///
1106 /// \usage
1107 /// For any type `T`,
1108 /// \code
1109 /// using result = tt::has_get_clone<T>;
1110 /// \endcode
1111 ///
1112 /// \metareturns
1113 /// cpp17::bool_constant
1114 ///
1115 /// \semantics
1116 /// If the type `T` has a `get_clone()` member function, then
1117 /// \code
1118 /// typename result::type = std::true_type;
1119 /// \endcode
1120 /// otherwise
1121 /// \code
1122 /// typename result::type = std::false_type;
1123 /// \endcode
1124 ///
1125 /// \example
1126 /// \snippet Utilities/Test_TypeTraits.cpp has_get_clone_example
1127 /// \see has_clone
1128 /// \tparam T the type to check
1129 template <typename T, typename = cpp17::void_t<>, typename = std::nullptr_t>
1130 struct has_get_clone : std::false_type {};
1131 /// \cond HIDDEN_SYMBOLS
1132 // The ugliness with two void template parameters is because clang does not
1133 // recognize the two decltype'd specializations as being different
1134 template <typename T>
1135 struct has_get_clone<
1136  T, cpp17::void_t<decltype(
1137  std::declval<std::remove_pointer_t<std::decay_t<T>>>().get_clone())>,
1138  Requires<not tt::is_a_v<std::unique_ptr, std::decay_t<T>> and
1139  not tt::is_a_v<std::shared_ptr, std::decay_t<T>>>>
1140  : std::true_type {};
1141 template <typename T>
1142 struct has_get_clone<T, cpp17::void_t<Requires<tt::is_a_v<std::unique_ptr, T>>,
1143  decltype(std::declval<T>()->get_clone())>,
1144  Requires<tt::is_a_v<std::unique_ptr, std::decay_t<T>> or
1145  tt::is_a_v<std::shared_ptr, std::decay_t<T>>>>
1146  : std::true_type {};
1147 /// \endcond
1148 /// \see has_get_clone
1149 template <typename T>
1151 
1152 /// \see has_get_clone
1153 template <typename T>
1155 // @}
1156 
1157 // @{
1158 /// \ingroup TypeTraitsGroup
1159 /// \brief Check if type `T` has a `clone()` member function
1160 ///
1161 /// \details
1162 /// Inherits from std::true_type if the type `T` has a `clone()` member
1163 /// function, otherwise inherits from std::false_type
1164 ///
1165 /// \usage
1166 /// For any type `T`,
1167 /// \code
1168 /// using result = tt::has_clone<T>;
1169 /// \endcode
1170 ///
1171 /// \metareturns
1172 /// cpp17::bool_constant
1173 ///
1174 /// \semantics
1175 /// If the type `T` has a `clone()` member function, then
1176 /// \code
1177 /// typename result::type = std::true_type;
1178 /// \endcode
1179 /// otherwise
1180 /// \code
1181 /// typename result::type = std::false_type;
1182 /// \endcode
1183 ///
1184 /// \example
1185 /// \snippet Utilities/Test_TypeTraits.cpp has_clone_example
1186 /// \see has_get_clone
1187 /// \tparam T the type to check
1188 template <typename T, typename = cpp17::void_t<>, typename = std::nullptr_t>
1190 /// \cond HIDDEN_SYMBOLS
1191 template <typename T>
1192 struct has_clone<T, cpp17::void_t<decltype(std::declval<T>().clone())>,
1193  Requires<not tt::is_a_v<std::unique_ptr, std::decay_t<T>> and
1194  not tt::is_a_v<std::shared_ptr, std::decay_t<T>>>>
1195  : std::true_type {};
1196 template <typename T>
1197 struct has_clone<T, cpp17::void_t<decltype(std::declval<T>()->clone())>,
1198  Requires<tt::is_a_v<std::unique_ptr, std::decay_t<T>> or
1199  tt::is_a_v<std::shared_ptr, std::decay_t<T>>>>
1200  : std::true_type {};
1201 /// \endcond
1202 /// \see has_clone
1203 template <typename T>
1205 
1206 /// \see has_clone
1207 template <typename T>
1209 // @}
1210 
1211 // @{
1212 /// \ingroup TypeTraitsGroup
1213 /// \brief Check if type `T` has a `size()` member function
1214 ///
1215 /// \details
1216 /// Inherits from std::true_type if the type `T` has a `size()` member
1217 /// function, otherwise inherits from std::false_type
1218 ///
1219 /// \usage
1220 /// For any type `T`,
1221 /// \code
1222 /// using result = tt::has_size<T>;
1223 /// \endcode
1224 /// \metareturns
1225 /// cpp17::bool_constant
1226 ///
1227 /// \semantics
1228 /// If the type `T` has a `size()` member function, then
1229 /// \code
1230 /// typename result::type = std::true_type;
1231 /// \endcode
1232 /// otherwise
1233 /// \code
1234 /// typename result::type = std::false_type;
1235 /// \endcode
1236 ///
1237 /// \example
1238 /// \snippet Utilities/Test_TypeTraits.cpp has_size_example
1239 /// \see is_iterable
1240 /// \tparam T the type to check
1241 template <typename T, typename = cpp17::void_t<>>
1243 /// \cond HIDDEN_SYMBOLS
1244 template <typename T>
1245 struct has_size<T, cpp17::void_t<decltype(std::declval<T>().size())>>
1246  : std::true_type {};
1247 /// \endcond
1248 /// \see has_size
1249 template <typename T>
1251 
1252 /// \see has_size
1253 template <typename T>
1255 // @}
1256 
1257 // @{
1258 /*!
1259  * \ingroup TypeTraitsGroup
1260  * \brief Check if `I` is an integer type (non-bool, non-character), unlike
1261  * std::is_integral
1262  *
1263  * \details
1264  * Inherits from `std::true_type` if `I` is a `short`, `unsigned short`,
1265  * `int`, `unsigned int`, `long`, `unsigned long`, `long long`, or
1266  * `unsigned long long`, otherwise inherits from `std::false_type`.
1267  *
1268  * \usage
1269  * For any type `I`,
1270  * \code
1271  * using result = tt::is_integer<I>;
1272  * \endcode
1273  * \metareturns
1274  * cpp17::bool_constant
1275  *
1276  * \example
1277  * \snippet Utilities/Test_TypeTraits.cpp is_integer_example
1278  * \see std::is_integral std::is_arithmetic std::is_floating_point
1279  */
1280 template <typename I>
1282 /// \cond HIDDEN_SYMBOLS
1283 template <>
1284 struct is_integer<short> : std::true_type {};
1285 template <>
1286 struct is_integer<unsigned short> : std::true_type {};
1287 
1288 template <>
1289 struct is_integer<int> : std::true_type {};
1290 template <>
1291 struct is_integer<unsigned int> : std::true_type {};
1292 
1293 template <>
1294 struct is_integer<long> : std::true_type {};
1295 template <>
1296 struct is_integer<unsigned long> : std::true_type {};
1297 
1298 template <>
1299 struct is_integer<long long> : std::true_type {};
1300 template <>
1301 struct is_integer<unsigned long long> : std::true_type {};
1302 /// \endcond
1303 
1304 /// \see is_integer
1305 template <typename T>
1307 // @}
1308 
1309 // @{
1310 /*!
1311  * \ingroup TypeTraitsGroup
1312  * \brief Gets the underlying type if the type is a std::reference_wrapper,
1313  * otherwise returns the type itself
1314  *
1315  * \usage
1316  * For any type `I`,
1317  * \code
1318  * using result = tt::remove_reference_wrapper<I>;
1319  * \endcode
1320  * \metareturns
1321  * either `I::type` if `I` is a std::reference_wrapper, else returns I
1322  *
1323  * \example
1324  * \snippet Utilities/Test_TypeTraits.cpp remove_reference_wrapper_example
1325  * \see std::reference_wrapper
1326  */
1327 template <typename T>
1329  using type = T;
1330 };
1331 /// \cond HIDDEN_SYMBOLS
1332 template <typename T>
1333 struct remove_reference_wrapper<std::reference_wrapper<T>> {
1334  using type = T;
1335 };
1336 template <typename T>
1337 struct remove_reference_wrapper<const std::reference_wrapper<T>> {
1338  using type = T;
1339 };
1340 template <typename T>
1341 struct remove_reference_wrapper<volatile std::reference_wrapper<T>> {
1342  using type = T;
1343 };
1344 template <typename T>
1345 struct remove_reference_wrapper<const volatile std::reference_wrapper<T>> {
1346  using type = T;
1347 };
1348 
1349 /// \endcond
1350 
1351 template <typename T>
1352 using remove_reference_wrapper_t = typename remove_reference_wrapper<T>::type;
1353 // @}
1354 
1355 // @{
1356 /*!
1357  * \ingroup TypeTraitsGroup
1358  * \brief Removes std::reference_wrapper, references, and cv qualifiers.
1359  *
1360  * \example
1361  * \snippet Utilities/Test_TypeTraits.cpp remove_cvref_wrap
1362  * \see std::reference_wrapper remove_reference_wrapper std::remove_cvref
1363  */
1364 template <typename T>
1366  using type = cpp20::remove_cvref_t<tt::remove_reference_wrapper_t<T>>;
1367 };
1368 
1369 template <typename T>
1370 using remove_cvref_wrap_t = typename remove_cvref_wrap<T>::type;
1371 // @}
1372 
1373 // @{
1374 /// \ingroup TypeTraitsGroup
1375 /// \brief Extracts the fundamental type for a container
1376 ///
1377 /// \details Designates a type alias `get_fundamental_type::type`
1378 /// as `T` when `T` itself is an appropriate fundamental type, and the
1379 /// contained type of a container which specifies a `value_type`.
1380 ///
1381 /// `get_fundamental_type_t<T>` is provided as a type alias to
1382 /// `type` from `get_fundamental_type<T>`
1383 template <typename T, typename Enable = cpp17::void_t<>>
1385  using type = tmpl::conditional_t<cpp17::is_fundamental_v<T>, T, NoSuchType>;
1386 };
1387 /// \cond
1388 template <typename T>
1389 struct get_fundamental_type<T, cpp17::void_t<typename T::value_type>> {
1390  using type = typename get_fundamental_type<typename T::value_type>::type;
1391 };
1392 /// \endcond
1393 template <typename T>
1394 using get_fundamental_type_t = typename get_fundamental_type<T>::type;
1395 // @}
1396 
1397 // @{
1398 /// \ingroup TypeTraitsGroup
1399 /// \brief Determines if a type `T` is a `std::complex` of a fundamental type,
1400 /// is a `std::true_type` if so, and otherwise is a `std::false_type`
1401 ///
1402 /// \snippet Test_TypeTraits.cpp is_complex_of_fundamental
1403 template <typename T, typename = cpp17::bool_constant<true>>
1405 /// \cond
1406 // this version will only pattern match if `T` is both complex and a fundamental
1407 // type
1408 template <typename T>
1410  std::complex<T>, cpp17::bool_constant<cpp17::is_fundamental_v<T>>>
1411  : std::true_type {};
1412 /// \endcond
1413 // @}
1414 template <typename T>
1415 constexpr bool is_complex_of_fundamental_v =
1417 
1418 /// \ingroup TypeTraitsGroup
1419 /// \brief Evaluates to `true` if type `T` is a `std::complex` of a fundamental
1420 /// type or if `T` is a fundamental type.
1421 template <typename T>
1423  is_complex_of_fundamental_v<T> or cpp17::is_fundamental_v<T>;
1424 
1425 namespace tt_detail {
1426 template <typename T>
1427 struct function_info_impl;
1428 
1429 template <typename Ret, typename... Args>
1430 struct function_info_impl<Ret(Args...)> {
1431  using return_type = Ret;
1432  using argument_types = tmpl::list<Args...>;
1433  using class_type = void;
1434 };
1435 
1436 template <typename Ret, typename... Args>
1437 struct function_info_impl<Ret (*)(Args...)> {
1438  using return_type = Ret;
1439  using argument_types = tmpl::list<Args...>;
1440  using class_type = void;
1441 };
1442 
1443 template <typename Ret, typename... Args>
1444 struct function_info_impl<Ret (*const)(Args...)> {
1445  using return_type = Ret;
1446  using argument_types = tmpl::list<Args...>;
1447  using class_type = void;
1448 };
1449 
1450 template <typename Ret, typename... Args>
1451 struct function_info_impl<Ret (*const volatile)(Args...)> {
1452  using return_type = Ret;
1453  using argument_types = tmpl::list<Args...>;
1454  using class_type = void;
1455 };
1456 
1457 template <typename Ret, typename... Args>
1458 struct function_info_impl<Ret (*volatile)(Args...)> {
1459  using return_type = Ret;
1460  using argument_types = tmpl::list<Args...>;
1461  using class_type = void;
1462 };
1463 
1464 template <typename Ret, typename Class, typename... Args>
1465 struct function_info_impl<Ret (Class::*)(Args...)> {
1466  using return_type = Ret;
1467  using argument_types = tmpl::list<Args...>;
1468  using class_type = Class;
1469 };
1470 
1471 template <typename Ret, typename Class, typename... Args>
1472 struct function_info_impl<Ret (Class::*)(Args...) const> {
1473  using return_type = Ret;
1474  using argument_types = tmpl::list<Args...>;
1475  using class_type = Class;
1476 };
1477 
1478 template <typename Ret, typename Class, typename... Args>
1479 struct function_info_impl<Ret (Class::*)(Args...) const volatile> {
1480  using return_type = Ret;
1481  using argument_types = tmpl::list<Args...>;
1482  using class_type = Class;
1483 };
1484 
1485 template <typename Ret, typename Class, typename... Args>
1486 struct function_info_impl<Ret (Class::*)(Args...) volatile> {
1487  using return_type = Ret;
1488  using argument_types = tmpl::list<Args...>;
1489  using class_type = Class;
1490 };
1491 } // namespace tt_detail
1492 
1493 /*!
1494  * \ingroup TypeTraitsGroup
1495  * \brief Returns a struct that contains the return type, argument types, and
1496  * the class type if the `F` is a non-static member function
1497  *
1498  * The return class has member type aliases:
1499  * - `return_type` The return type of the function
1500  * - `argument_types` A `tmpl::list` of the arguments types of the function
1501  * - `class_type` The type of the class if the function is a non-static member
1502  * function, otherwise `void`
1503  *
1504  * \note For static member variables the class will be `void` because they are
1505  * effectively free functions.
1506  */
1507 template <typename F>
1508 using function_info = tt_detail::function_info_impl<F>;
1509 
1510 /*!
1511  * \ingroup TypeTraitsGroup
1512  * \brief Given a type `T` and possibly a `size_t` evaluates to `T`. Useful for
1513  * turning a `std::index_sequence` into a pack expansion of types.
1514  *
1515  * \snippet Test_TypeTraits.cpp example_identity_t
1516  */
1517 template <typename T, size_t = 0>
1518 using identity_t = T;
1519 } // namespace tt
constexpr bool is_iterable_v
Definition: TypeTraits.hpp:591
Check if type T has a clone() member function.
Definition: TypeTraits.hpp:1189
typename is_comparable< T >::type is_comparable_t
Definition: TypeTraits.hpp:649
Mark a return type as being "void". In C++17 void is a regular type under certain circumstances...
Definition: TypeTraits.hpp:47
typename is_std_array< T >::type is_std_array_t
Definition: TypeTraits.hpp:455
Check if type T has operator== defined.
Definition: TypeTraits.hpp:722
typename is_iterable< T >::type is_iterable_t
Definition: TypeTraits.hpp:595
Extracts the fundamental type for a container.
Definition: TypeTraits.hpp:1384
constexpr bool disjunction_v
Definition: TypeTraits.hpp:156
decltype(TypeTraits_detail::array_size_impl(std::declval< const Array & >())) array_size
Get the size of a std::array as a std::integral_constant.
Definition: TypeTraits.hpp:687
void void_t
Given a set of types, returns void
Definition: TypeTraits.hpp:214
typename has_inequivalence< T >::type has_inequivalence_t
Definition: TypeTraits.hpp:783
Check if a type T is callable, i.e. T(Args...) is evaluable.
Definition: TypeTraits.hpp:819
Negate a bool_constant.
Definition: TypeTraits.hpp:185
Check if T is copy constructible.
Definition: TypeTraits.hpp:398
C++ STL code present in C++20.
Definition: Algorithm.hpp:11
typename has_get_clone< T >::type has_get_clone_t
Definition: TypeTraits.hpp:1154
Check if type T has a size() member function.
Definition: TypeTraits.hpp:1242
constexpr bool is_std_array_v
Definition: TypeTraits.hpp:451
typename has_size< T >::type has_size_t
Definition: TypeTraits.hpp:1254
Check if type T has operator<<(S, T) defined.
Definition: StlStreamDeclarations.hpp:32
constexpr bool is_integer_v
Definition: TypeTraits.hpp:1306
Declares stream operators for STL containers.
Defines the type alias Requires.
Check if std::hash and std::equal_to are defined for type T.
Definition: TypeTraits.hpp:925
typename is_callable< T, Args... >::type is_callable_t
Definition: TypeTraits.hpp:848
A collection of useful type traits.
Definition: TensorExpression.hpp:115
typename is_std_array_of_size< N, T >::type is_std_array_of_size_t
Definition: TypeTraits.hpp:501
A logical AND on the template parameters.
Definition: TypeTraits.hpp:97
constexpr bool is_hashable_v
Definition: TypeTraits.hpp:934
constexpr bool is_comparable_v
Definition: TypeTraits.hpp:645
typename has_equivalence< T >::type has_equivalence_t
Definition: TypeTraits.hpp:735
constexpr bool is_callable_v
Definition: TypeTraits.hpp:844
Removes std::reference_wrapper, references, and cv qualifiers.
Definition: TypeTraits.hpp:1365
Used to mark "no type" or "bad state" for metaprogramming.
Definition: NoSuchType.hpp:10
constexpr bool is_complex_or_fundamental_v
Evaluates to true if type T is a std::complex of a fundamental type or if T is a fundamental type...
Definition: TypeTraits.hpp:1422
typename is_maplike< T >::type is_maplike_t
Definition: TypeTraits.hpp:992
constexpr bool is_std_array_of_size_v
Definition: TypeTraits.hpp:497
Check if type T has a begin() and end() function.
Definition: TypeTraits.hpp:582
constexpr bool is_same_v
Variable template for is_same.
Definition: TypeTraits.hpp:221
constexpr bool is_a_v
Definition: TypeTraits.hpp:543
typename has_clone< T >::type has_clone_t
Definition: TypeTraits.hpp:1208
constexpr bool has_inequivalence_v
Definition: TypeTraits.hpp:779
Check if type T is a std::array of a given size.
Definition: TypeTraits.hpp:490
constexpr bool conjunction_v
Definition: TypeTraits.hpp:108
typename is_hashable< T >::type is_hashable_t
Definition: TypeTraits.hpp:938
constexpr bool has_clone_v
Definition: TypeTraits.hpp:1204
Check if type T is a template specialization of U
Definition: TypeTraits.hpp:536
Check if type T is a std::array.
Definition: TypeTraits.hpp:444
Definition: TypeTraits.hpp:373
constexpr bool is_maplike_v
Definition: TypeTraits.hpp:988
Wraps the template metaprogramming library used (brigand)
Check if type T has a get_clone() member function.
Definition: TypeTraits.hpp:1130
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
Determines if a type T is a std::complex of a fundamental type, is a std::true_type if so...
Definition: TypeTraits.hpp:1404
T identity_t
Given a type T and possibly a size_t evaluates to T. Useful for turning a std::index_sequence into a ...
Definition: TypeTraits.hpp:1518
C++ STL code present in C++17.
Definition: Array.hpp:16
typename is_a< U, Args... >::type is_a_t
Definition: TypeTraits.hpp:547
Check if type T has <, <=, >, >=, ==, !=.
Definition: TypeTraits.hpp:631
Gets the underlying type if the type is a std::reference_wrapper, otherwise returns the type itself...
Definition: TypeTraits.hpp:1328
constexpr bool has_equivalence_v
Definition: TypeTraits.hpp:731
Check if type T has operator!= defined.
Definition: TypeTraits.hpp:770
A logical OR on the template parameters.
Definition: TypeTraits.hpp:145
constexpr bool has_size_v
Definition: TypeTraits.hpp:1250
Check if I is an integer type (non-bool, non-character), unlike std::is_integral. ...
Definition: TypeTraits.hpp:1281
tt_detail::function_info_impl< F > function_info
Returns a struct that contains the return type, argument types, and the class type if the F is a non-...
Definition: TypeTraits.hpp:1508
Check if type T is like a std::map or std::unordored_map.
Definition: TypeTraits.hpp:976
constexpr bool has_get_clone_v
Definition: TypeTraits.hpp:1150