TupleLookupByTag.h
Go to the documentation of this file.
1 /**
2  * @file TupleLookupByTag.h
3  * @brief Utilities to address elements of a tuple-like class by tag.
4  * @author Gianluca Petrillo
5  * @date August 17, 2018
6  *
7  * A "tagged" class is a class containing a type named "tag". The class is
8  * tagged by it. A container of objects, tuple-like, can be accessed by
9  * specifying the type of the tag. For example:
10  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
11  * std::tuple<TaggedItem1, TaggedItem2, TaggedItem3> data;
12  *
13  * auto tagBdata = util::getByTag<TagB>(data);
14  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15  * will assign tagBdata with one of the three components of the `data` objects,
16  * the one whose type has `tag` equal to `TagB`.
17  *
18  * The type being processed must be "tuple-like" (in the example above, the type
19  * of `data` is in fact a tuple). This means that the type must respond to
20  * `std::tuple_element` and `std::tuple_size`.
21  *
22  * Beside these utilities, equivalent utilities are exposed that allow a
23  * different definition of the tag (via a class "returning" the tag of its
24  * only template argument), and that operate on the types directly rather than
25  * on the tags (equivalent to define the tag as the object itself).
26  *
27  * All the type trait utilities follow the standard C++ convention: the ones
28  * "returning" a type have that type in a `type` member, and the ones returning
29  * a value have that value in a `value` member, and their instances can be
30  * implicitly converted to that value. Aliases ending with `_t` and `_v` are
31  * also provided.
32  *
33  * This is a header-only library providing mostly type trait information.
34  *
35  */
36 
37 #ifndef LARDATA_UTILITIES_TUPLELOOKUPBYTAG_H
38 #define LARDATA_UTILITIES_TUPLELOOKUPBYTAG_H
39 
40 // LArSoft libraries
42 
43 // C/C++ standard libraries
44 #include <tuple>
45 #include <type_traits>
46 #include <cstddef> // std::size_t
47 
48 /**
49  * @addtogroup Utilities General utilities
50  * @brief General programming utilities.
51  *
52  * @{
53  */
54 /**
55  * @namespace util
56  * @brief Namespace for general, not LArSoft-specific utilities.
57  */
58 /**
59  * @addtogroup Metaprogramming General utilities for metaprogramming
60  * @brief General utilities for use with templates and metaprogramming.
61  */
62 /**
63  * @}
64  */
65 
66 namespace util {
67 
68  namespace details {
69 
70  //--------------------------------------------------------------------------
71  // forward declaration of implementation details
72  //--------------------------------------------------------------------------
73  //--- General utilities
74  //--------------------------------------------------------------------------
75  template <typename Target, typename... T>
77 
78  template <typename Target, typename... T>
80 
81 
82  //--------------------------------------------------------------------------
83  //--- Courtesy traits
84  //--------------------------------------------------------------------------
85  template <typename Tuple>
87 
88 
89  //--------------------------------------------------------------------------
90  //--- Tagging
91  //--------------------------------------------------------------------------
92  template <typename Tagged, typename = void>
94 
95 
96  //--------------------------------------------------------------------------
97 
98  } // namespace details
99 
100 
101  //--- BEGIN Metaprogramming --------------------------------------------------
102  /// @ingroup MetaprogrammingBase
103  /// @{
104 
105  /// Returns how many of the types in `T` exactly match `Target`.
106  template <typename Target, typename... T>
108 
109  /// Direct access to the value in `count_type_in_list`.
110  template <typename Target, typename... T>
111  constexpr unsigned int count_type_in_list_v
112  = count_type_in_list<Target, T...>();
113 
114  /// Returns the `N` type of the type list.
115  template <std::size_t N, typename... T>
116  using typelist_element_type = std::tuple_element<N, std::tuple<T...>>;
117 
118  /// Direct access to the value in `typelist_element_type`.
119  template <std::size_t N, typename... T>
121 
122 
123  /// Holds whether the `Target` type is among the ones in the `T` pack.
124  template <typename Target, typename... T>
125  using type_is_in = details::type_is_in_impl<Target, T...>;
126 
127  /// Direct access to the value in `type_is_in`.
128  template <typename Target, typename... T>
129  constexpr bool type_is_in_v = type_is_in<Target, T...>();
130 
131 
132  /// Holds whether the `Target` type is element of the specified `std::tuple`.
133  template <typename Target, typename Tuple>
135 
136  /// @}
137  //--- END Metaprogramming ----------------------------------------------------
138 
139 
140  //----------------------------------------------------------------------------
141  /**
142  * @defgroup MetaprogrammingGeneral General utility traits
143  * @brief Traits of general utility.
144  * @ingroup Metaprogramming
145  * @{
146  *
147  * @details These traits are used in the implementation of the tag-related
148  * traits, but they are general enough that are deemed worth being exposed.
149  */
150 
151 
152  //----------------------------------------------------------------------------
153  /**
154  * @brief Returns type `TargetClass<U...>` from a `SrcTuple<T...>`.
155  * @tparam SrcTuple a tuple-like type enclosing a list of types
156  * @tparam Extractor class extracting the `U` type from each `T`
157  * @tparam TargetClass the template type of the class to be returned
158  * @see `extract_to_tuple_type_t`, `to_tuple`
159  *
160  * The input template argument `SrcTuple` is an object supporting
161  * `std::tuple_size` and `std::tuple_element` to return all its contained
162  * types.
163  *
164  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
165  * template <typename... T>
166  * struct MyFirstClass {
167  * // ...
168  * };
169  *
170  * template <typename... T>
171  * struct MySecondClass {
172  * // ...
173  * };
174  *
175  * using DataClass = MyFirstDataClass<int, char, std::string>;
176  * using PointerDataClass = util::extract_to_tuple_type
177  * <DataClass, std::add_pointer, MySecondClass>;
178  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179  * will yield a `PointerDataClass` as
180  * `MySecondClass<int*, char*, std::string*>` (note that in this partial
181  * example `MyFirstClass` is not yet a tuple-like type).
182  *
183  * The extractor is a trait whose first element is the type to be transformed,
184  * and whose member `type` holds the transformed type.
185  *
186  * @note The extractor must be able to return a type for each and every type
187  * in `SrcTuple`.
188  *
189  */
190  template <
191  typename SrcTuple,
192  template <typename T, typename...> class Extractor,
193  template <typename...> class TargetClass = std::tuple
194  >
196 
197 
198  /// Direct access to the type in `extract_to_tuple_type`.
199  template <
200  typename SrcTuple,
201  template <typename T, typename...> class Extractor,
202  template <typename...> class TargetClass = std::tuple
203  >
206 
207 
208  /// `extract_to_tuple_type` with no `T`-to-`U` type transformation.
209  /// @see `extract_to_tuple_type`, `to_tuple_t`
210  template
211  <typename Tuple, template <typename...> class TargetClass = std::tuple>
213 
214  /// Direct access to the type in `to_tuple`.
215  template
216  <typename Tuple, template <typename...> class TargetClass = std::tuple>
218 
219 
220  //----------------------------------------------------------------------------
221  /**
222  * @brief Returns the index of the element in `Tuple` with the specified type.
223  * @tparam Extractor extract the candidate type from a `Tuple` element
224  * @tparam Target the type being sought
225  * @tparam Tuple tuple-like data structure containing types.
226  * @see `index_of_extracted_type_v`, `has_extracted_type`,
227  * `count_extracted_types`, `has_type`,
228  *
229  * Given a tuple-like type `Tuple`, this traits returns the index of the one
230  * element type which "contains" the target type `Target`.
231  * For example:
232  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
233  * template <typename T>
234  * struct ExtractValueType { using type = typename T::value_type; };
235  *
236  * using tuple_t = std::tuple<std::vector<std::string>, std::vector<int>>;
237  *
238  * constexpr std::size_t IntegersIndex
239  * = util::index_of_extracted_type<ExtractValueType, int, tuple_t>();
240  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241  * `IntegersIndex` will hold value `1`, pointing to the container in `tuple_t`
242  * with `int` as `value_type`.
243  *
244  * If the target type is not present, or if it is present more than once, a
245  * compilation error will ensue.
246  *
247  * @note Currently there is no equivalent trait to ask for the index of the
248  * second or following type; this can be implemented on request.
249  */
250  template<
251  template <typename T, typename...> class Extractor,
252  typename Target,
253  typename Tuple
254  >
256 
257  /// Direct access to the value in `index_of_extracted_type`.
258  template<
259  template <typename T, typename...> class Extractor,
260  typename Target,
261  typename Tuple
262  >
263  constexpr std::size_t index_of_extracted_type_v
265 
266 
267  /// Like `index_of_extracted_type`, but querying the element types directly.
268  /// @see `index_of_extracted_type`, `index_of_type_v`, `has_type`,
269  /// `count_types`
270  template <typename Target, typename Tuple>
272 
273 
274  /// Direct access to the value in `index_of_type`.
275  template <typename Target, typename Tuple>
277 
278 
279  //----------------------------------------------------------------------------
280  /**
281  * @brief Returns the element type in `Tuple` with the specified type.
282  * @tparam Extractor extract the candidate type from a `Tuple` element
283  * @tparam Target the type being sought
284  * @tparam Tuple tuple-like data structure containing types.
285  * @see `type_with_extracted_type_t`, `index_of_extracted_type`,
286  * `has_extracted_type`, `count_extracted_types`, `has_type`,
287  *
288  * Given a tuple-like type `Tuple`, this traits returns the one element type
289  * which "contains" the target type `Target`.
290  * For example:
291  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
292  * template <typename T>
293  * struct ExtractValueType { using type = typename T::value_type; };
294  *
295  * using tuple_t = std::tuple<std::vector<std::string>, std::vector<int>>;
296  *
297  * using int_container_t
298  * = util::type_with_extracted_type<ExtractValueType, int, tuple_t>();
299  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
300  * `int_container_t` will be `std::vector<int>`, as the type in `tuple_t`
301  * with `int` as `value_type`.
302  *
303  * If the target type is not present, or if it is present more than once, a
304  * compilation error will ensue.
305  *
306  * @note Currently there is no equivalent trait to ask for the second or
307  * following type; this can be implemented on request.
308  */
309  template<
310  template <typename T, typename...> class Extractor,
311  typename Target,
312  typename Tuple
313  >
314  using type_with_extracted_type = std::tuple_element
315  <index_of_extracted_type_v<Extractor, Target, Tuple>, Tuple>;
316 
317  /// Direct access to the value in `type_with_extracted_type`.
318  template<
319  template <typename T, typename...> class Extractor,
320  typename Target,
321  typename Tuple
322  >
325 
326 
327  //----------------------------------------------------------------------------
328  /**
329  * @brief Trait holding whether an element in `Tuple` type contains `Target`.
330  * @tparam Extractor trait exposing the target type in an element
331  * @tparam Target the target type to be found
332  * @tparam Tuple the tuple-like type to be investigated
333  * @see `has_extracted_type_v`, `index_of_extracted_type`,
334  * `count_extracted_types`, `has_type`
335  *
336  * Given a tuple-like type `Tuple`, this trait returns whether there is at
337  * least an element type which "contains" the target type `Target`.
338  * For example:
339  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
340  * template <typename T>
341  * struct ExtractValueType { using type = typename T::value_type; };
342  *
343  * using tuple_t
344  * = std::tuple<std::vector<float>, std::vector<int>, std::list<int>>;
345  *
346  * constexpr bool hasIntegerContainers
347  * = util::has_extracted_type<ExtractValueType, int, tuple_t>();
348  * constexpr bool hasDoubleContainers
349  * = util::has_extracted_type<ExtractValueType, double, tuple_t>();
350  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
351  * `hasIntegerContainers` will hold value `true`, meaning there are two types
352  * with `int` as `value_type`. Likewise, `hasDoubleContainers` will be
353  * `false`.
354  *
355  * @note Before C++17, the following construct is invalid:
356  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
357  * using tuple_t
358  * = std::tuple<std::vector<float>, std::vector<int>, std::list<int>>;
359  * tuple_t data {
360  * { 0.5, 1.5 },
361  * { 0, 2, 4 },
362  * { 1, 3, 5 }
363  * };
364  * if (util::has_extracted_type<ExtractValueType, int, tuple_t>())
365  * return util::getByExtractedType<ExtractValueType, int>(data);
366  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
367  * because `util::getByExtractedType<ExtractValueType, double>(data)`
368  * needs to be compilable, but it is not since it has more than one
369  * `int` extracted types. This is solved in C++17 by the use of a
370  * "constexpr if".
371  */
372  template<
373  template <typename T, typename...> class Extractor,
374  typename Target,
375  typename Tuple
376  >
378 
379  /// Direct access to the value in `has_extracted_type`.
380  template<
381  template <typename T, typename...> class Extractor,
382  typename Target,
383  typename Tuple
384  >
385  constexpr bool has_extracted_type_v
387 
388 
389  /// Like `has_extracted_type`, but querying the element types directly.
390  /// @see `has_extracted_type`, `index_of_type`, `count_types`, `has_type_v`
391  template <typename Target, typename Tuple>
393 
394  /// Direct access to the value in `has_type`.
395  template<typename Target, typename Tuple>
397 
398 
399  //----------------------------------------------------------------------------
400  /**
401  * @brief Returns the value of the element containing the specified type.
402  * @tparam Extractor trait extracting the target type from an element
403  * @tparam Target the type sought
404  * @tparam Tuple a tuple-like type to get values from
405  * @param data the tuple to get data from
406  * @return the value of the element containing the specified `Target` type
407  * @see `count_extracted_types`, `index_of_extracted_type`,
408  * `has_extracted_type`
409  *
410  * The value of the selected element in `data` is returned, as in `std::get`.
411  * The value is taken from the element of data which contains the target type
412  * `Target`. The target type is extracted from each element in turn, using the`
413  * `Extractor` trait.
414  *
415  * This function has the same limitations as `util::index_of_extracted_type`.
416  *
417  * In the example:
418  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
419  * template <typename T>
420  * struct ExtractValueType { using type = typename T::value_type; };
421  *
422  * auto myData = std::make_tuple(
423  * std::vector<float>{ 1.5, 2.5 },
424  * std::vector<int>{ 0, 2, 4 },
425  * std::list<int>{ 1, 3, 5 }
426  * );
427  *
428  * decltype(auto) realData
429  * = util::getByExtractedType<ExtractValueType, float>(data);
430  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
431  * `realData` will be a reference `std::vector<float>&` to the element
432  * containing `{ 1.5, 2.5 }`. Also note that in this example requesting the
433  * data of value type `int` will cause a compilation error since there is more
434  * than one element with that value type.
435  */
436  template <
437  template <typename T, typename...> class Extractor,
438  typename Target,
439  typename Tuple>
440  auto getByExtractedType(Tuple const& data) -> decltype(auto);
441 
442 
443  /**
444  * @brief Traits holding whether elements of `Tuple` have duplicate types.
445  * @tparam Extractor trait to extract the type to check from each element
446  * @tparam Tuple tuple-type object to check
447  * @see `count_extracted_types_v`, `index_of_extracted_type`,
448  * `has_extracted_type`,
449  * `has_duplicate_types`, `has_duplicate_extracted_types_v`
450  *
451  * This trait holds whether there are multiple occurrences of elements in
452  * `Tuple` which have the same extracted type.
453  * For example:
454  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
455  * template <typename T>
456  * struct ExtractValueType { using type = typename T::value_type; };
457  *
458  * using tuple_t
459  * = std::tuple<std::vector<float>, std::vector<int>, std::list<int>>;
460  *
461  * constexpr bool hasDuplicate
462  * = util::has_duplicate_extracted_types<ExtractValueType, tuple_t>();
463  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
464  * `hasDuplicate` is `true` because there are two elements in `tuple_t` with
465  * `int` as `value_type` (that is, the type delivered by `ExtractValueType`).
466  */
467  template <template <typename T, typename...> class Extractor, typename Tuple>
470  <extract_to_tuple_type_t<Tuple, Extractor>>
471  {};
472 
473  /// Direct access to the value in `has_duplicate_extracted_types`.
474  template <template <typename T, typename...> class Extractor, typename Tuple>
475  constexpr bool has_duplicate_extracted_types_v
477 
478 
479  /// Like `has_duplicate_extracted_types`, but on the element types directly.
480  /// @see `has_duplicate_extracted_types`, `index_of_type`, `count_types`,
481  /// `has_types`, `has_duplicate_types_v`
482  template <typename Tuple>
484 
485  /// Direct access to the value in `has_duplicate_types`.
486  template <typename Tuple>
488 
489 
490  /**
491  * @brief Counts the elements of a tuple-like type containing a `Target` type.
492  * @tparam Extractor trait exposing the target type in an element
493  * @tparam Target the target type to be counted
494  * @tparam Tuple the tuple-like type to be investigated
495  * @see `count_extracted_types_v`, `index_of_extracted_type`,
496  * `has_extracted_type`, `count_types`
497  *
498  * Given a tuple-like type `Tuple`, this trait returns how many of its
499  * elements "contain" the target type `Target`.
500  * For example:
501  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
502  * template <typename T>
503  * struct ExtractValueType { using type = typename T::value_type; };
504  *
505  * using tuple_t
506  * = std::tuple<std::vector<float>, std::vector<int>, std::list<int>>;
507  *
508  * constexpr unsigned int nIntegerContainers
509  * = util::count_extracted_types<ExtractValueType, int, tuple_t>();
510  * constexpr unsigned int nDoubleContainers
511  * = util::count_extracted_types<ExtractValueType, double, tuple_t>();
512  * constexpr unsigned int nFloatContainers
513  * = util::count_extracted_types<ExtractValueType, float, tuple_t>();
514  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
515  * `nIntegerContainers` will hold value `2`, meaning there are two types
516  * with `int` as `value_type`. Likewise, `nDoubleContainers` will be `1`
517  * and `nFloatContainers` will be `0`.
518  */
519  template <
520  template <typename T, typename...> class Extractor,
521  typename Target,
522  typename Tuple
523  >
525 
526  /// Direct access to the value in `count_extracted_types`.
527  template <
528  template <typename T, typename...> class Extractor,
529  typename Target,
530  typename Tuple
531  >
532  constexpr unsigned int count_extracted_types_v
534 
535 
536  /// Counts the number of `Target` elements in the specified `Tuple`.
537  /// @see `count_extracted_types`, `index_of_extracted_type_v`,
538  /// `has_extracted_type_v`, `count_types_v`
539  template <typename Target, typename Tuple>
541 
542  /// Direct access to the value in `count_extracted_types`.
543  template <typename Target, typename Tuple>
544  constexpr unsigned int count_types_v = count_types<Target, Tuple>();
545 
546  /// @}
547 
548 
549  /**
550  * @defgroup MetaprogrammingTagged Tag-related traits
551  * @brief Traits for types with a `tag`.
552  * @ingroup Metaprogramming
553  *
554  * @details Tag-related traits operate on "tagged" types. A tagged type is a
555  * type which contains a `tag` type definition, and that type is the tag type.
556  *
557  * In the examples, the types used are defined as:
558  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
559  * struct TagA {};
560  * struct TagB {};
561  * struct TagC {};
562  * struct TagD {};
563  *
564  * using IntTaggedA = util::add_tag_t<std::vector<int>, TagA>;
565  * using DoubleTaggedB = util::add_tag_t<std::vector<double>, TagB>;
566  * using StringTaggedC = util::add_tag_t<std::string, TagC>;
567  * using ComplexTaggedA = util::add_tag_t<std::complex<float>, TagA>;
568  *
569  * using Tuple_t = std::tuple<IntTaggedA, DoubleTaggedB, StringTaggedC>;
570  * using DuplTuple_t = std::tuple<IntTaggedA, DoubleTaggedB, ComplexTaggedA>;
571  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
572  * Note that `DuplTuple_t` has two elements with the same tag (`TagA`).
573  *
574  * @note All the traits and function here will generate a compilation error
575  * if any of the elements is not tagged.
576  *
577  * @{
578  */
579 
580  /**
581  * @brief A type with a specified tag.
582  * @tparam T the base type being tagged
583  * @tparam Tag the tag to be assigned to the new type
584  * @see `add_tag`, `TagExtractor`
585  *
586  * The new type `TaggedType<T, Tag>` inherits from `T` (including its
587  * constructors) and adds (and hides existing) `tag` type with value `Tag`.
588  * This type is suitable to be used in the tag-related traits.
589  *
590  * For example:
591  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
592  * struct VectorTag {};
593  * using TaggedVector = TaggedType<std::vector<int>, VectorTag>;
594  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
595  */
596  template <typename T, typename Tag>
597  struct TaggedType: public T {
598 
599  // Forward all constructors
600  template <typename... Args>
601  TaggedType(Args&&... args): T(std::forward<Args>(args)...) {}
602 
603  using tag = Tag; ///< Tag of this object.
604  using tagged_type = T; ///< Type of the object which was tagged.
605 
606  }; // struct TaggedType
607 
608 
609  /// Trait holding a type derived from `T`, tagged with `Tag`.
610  /// @see `TaggedType`
611  template <typename T, typename Tag>
613 
614  /// Direct access to the type contained in `add_tag`.
615  /// @see `TaggedType`
616  template <typename T, typename Tag>
618 
619 
620  /// Trait holding the type contained in a `TaggedType` (or the type itself).
621  template <typename Tagged>
622  struct remove_tag { using type = Tagged; };
623 
624  template <typename T, typename Tag>
626  { using type = typename TaggedType<T, Tag>::tagged_type; };
627 
628  /// Direct access to the type contained in `remove_tag`.
629  template <typename Tagged>
631 
632 
633  /**
634  * @brief "Converts" `obj` to an object with tag `Tag`.
635  * @tparam Tag tag to be added to the object
636  * @tparam T type of the object to be tagged (implicitly deduced)
637  * @param obj (l-value) reference to the object to be tagged
638  * @return a reference to `obj`, reinterpreted as tagged
639  * @see `TaggedType`, `add_tag`
640  *
641  * The returned object is the same as `obj`, reinterpreted as a different type
642  * derived from `T` and tagged with `Tag`.
643  */
644  template <typename Tag, typename T>
645  auto makeTagged(T& obj) -> decltype(auto)
646  { return static_cast<add_tag_t<T, Tag>&>(obj); }
647 
648  /**
649  * @brief "Converts" `obj` to an object with tag `Tag`.
650  * @tparam Tag tag to be added to the object
651  * @tparam T type of the object to be tagged (implicitly deduced)
652  * @param obj (l-value) constant reference to the object to be tagged
653  * @return a reference to `obj`, reinterpreted as tagged
654  * @see `TaggedType`, `add_tag`
655  *
656  * The returned object is the same as `obj`, reinterpreted as a different type
657  * derived from `T` and tagged with `Tag`.
658  */
659  template <typename Tag, typename T>
660  auto makeTagged(T const& obj) -> decltype(auto)
661  { return static_cast<add_tag_t<T const, Tag> const&>(obj); }
662 
663  /**
664  * @brief "Converts" `obj` to an object with tag `Tag`.
665  * @tparam Tag tag to be added to the object
666  * @tparam T type of the object to be tagged (implicitly deduced)
667  * @param obj (r-value) reference to the object to be tagged
668  * @return a reference to `obj`, reinterpreted as tagged
669  * @see `TaggedType`, `add_tag`
670  *
671  * The returned object is an object of a new type, derived from `T` , with
672  * data copied from `obj`, and tagged with `Tag`.
673  * The argument object may be a temporary.
674  */
675  template <typename Tag, typename T>
676  auto makeTagged(T const&& obj) -> decltype(auto)
677  { return add_tag_t<T, Tag>(obj); /* copy, since it's constant */ }
678 
679  /**
680  * @brief "Converts" `obj` to an object with tag `Tag`.
681  * @tparam Tag tag to be added to the object
682  * @tparam T type of the object to be tagged (implicitly deduced)
683  * @param obj the object to be tagged
684  * @return a reference to `obj`, reinterpreted as tagged
685  * @see `TaggedType`, `add_tag`
686  *
687  * The returned object is the same as `obj`, reinterpreted as a different type
688  * derived from `T` and tagged with `Tag`.
689  * The returned object is a temporary of the new type, whose content is moved
690  * (`std::move()`) from the argument object `obj`.
691  */
692  template <typename Tag, typename T>
693  auto makeTagged(T&& obj) -> decltype(auto)
694  { return add_tag_t<T, Tag>(std::move(obj)); }
695 
696  /// "Converts" a tagged type back to its original type.
697  template <typename Tagged>
698  auto removeTag(Tagged& tagged) -> decltype(auto)
699  { return static_cast<remove_tag_t<Tagged>&>(tagged); }
700 
701  /// "Converts" a tagged type back to its original type.
702  template <typename Tagged>
703  auto removeTag(Tagged const& tagged) -> decltype(auto)
704  { return static_cast<remove_tag_t<Tagged> const&>(tagged); }
705 
706  /// "Converts" a tagged type back to its original type.
707  template <typename Tagged>
708  auto removeTag(Tagged const&& tagged) -> decltype(auto)
709  { return static_cast<remove_tag_t<Tagged> const&&>(tagged); }
710 
711  /// "Converts" a tagged type back to its original type.
712  template <typename Tagged>
713  auto removeTag(Tagged&& tagged) -> decltype(auto)
714  { return static_cast<remove_tag_t<Tagged>&&>(tagged); }
715 
716 
717  /// Tag class parametrized by a sequence of numbers.
718  template <std::size_t...>
719  struct TagN {};
720 
721 
722  /**
723  * @brief Extracts the tag from a type.
724  * @tparam Tagged type of tagged type
725  *
726  * This trait holds the tag type of `Tagged` (that is, `Tagged::tag`) as
727  * `type` member.
728  * If `Tagged` type has no `tag` type member, a compilation error will ensue.
729  */
730  template <typename Tagged>
732 
733  /// Trait holding the tag of `Tagged` as `type`.
734  template <typename Tagged>
736 
737  /// Direct access to the type in `tag_of`.
738  template <typename Tagged>
739  using tag_of_t = typename tag_of<Tagged>::type;
740 
741 
742  /// Returns a tuple with all the tags from `SrcTuple`.
743  template <typename SrcTuple>
745 
746  /// Direct access to the type in `extract_tags`.
747  template <typename SrcTuple>
749 
750 
751  /**
752  * @brief Trait holding the index of the element of `Tuple` with tag `Tag`.
753  * @tparam Tag the sought tag
754  * @tparam Tuple the tuple-like type holding the elements to check
755  * @see `index_of_tag_v`, `count_tags`, `has_duplicate_tags`, `has_tag`
756  *
757  * Given a tuple-like type `Tuple`, this traits returns the index of the one
758  * element type tagged with `Tag`.
759  * If the target type is not present, or if it is present more than once, a
760  * compilation error will ensue.
761  *
762  * For example (see above for the definitions):
763  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
764  * constexpr std::size_t TagAindex = util::index_of_tag<TagA, Tuple_t>();
765  * constexpr std::size_t TagBindex = util::index_of_tag<TagB, Tuple_t>();
766  * constexpr std::size_t TagBduplIndex
767  * = util::index_of_tag<TagB, DuplTuple_t>();
768  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
769  * `TagAindex` will hold value `0`, pointing to the container in `Tuple_t`
770  * of type `IntTaggedA`, while `TagBindex` will be `1` and `TagBduplIndex`
771  * will be also `1`. Instead, the expression
772  * `util::index_of_tag<TagD, Tuple_t>()` would not compile because no element
773  * in `Tuple_t` is tagged with `TagD`, and the expression
774  * `util::index_of_tag<TagA, DuplTuple_t>()` would not compile because two
775  * elements of `DuplTuple_t` are tagged `TagA`.
776  *
777  * @note Currently there is no equivalent trait to ask for the index of the
778  * second or following type, allowing for duplicate tags; this can be
779  * implemented on request.
780  */
781  template <typename Tag, typename Tuple>
783 
784 
785  /// Direct access to the value in `index_of_tag`.
786  template <typename Tag, typename Tuple>
787  constexpr std::size_t index_of_tag_v = index_of_tag<Tag, Tuple>();
788 
789 
790  /**
791  * @brief Trait holding the type of the element of `Tuple` with tag `Tag`.
792  * @tparam Tag the sought tag
793  * @tparam Tuple the tuple-like type holding the elements to check
794  * @see `type_with_tag_t`, `index_of_tag`, `count_tags`, `has_duplicate_tags`,
795  * `has_tag`
796  *
797  * Given a tuple-like type `Tuple`, this traits returns the one element type
798  * tagged with `Tag`.
799  * If the target type is not present, or if it is present more than once, a
800  * compilation error will ensue.
801  *
802  * For example (see above for the definitions):
803  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
804  * using TagA_t = typename util::type_with_tag<TagA, Tuple_t>::type;
805  * using TagB_t = typename util::type_with_tag<TagB, Tuple_t>::type;
806  * using TagBdupl_t = typename util::type_with_tag<TagB, DuplTuple_t>::type;
807  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
808  * `TagA_t` will be `IntTaggedA`, the type in `Tuple_t` with `TagA`, while
809  * `TagB_t` will be `DoubleTaggedB` and `TagBdupl_t` will be also
810  * `DoubleTaggedB`. Instead, the type `util::type_with_tag<TagD, Tuple_t>`
811  * would not compile because no element in `Tuple_t` is tagged with `TagD`,
812  * and the type `util::type_with_tag<TagA, DuplTuple_t>()` would not compile
813  * because two elements of `DuplTuple_t` are tagged `TagA`.
814  *
815  * @note Currently there is no equivalent trait to ask for the second or
816  * following type, allowing for duplicate tags; this can be implemented
817  * on request.
818  */
819  template <typename Tag, typename Tuple>
821 
822 
823  /// Direct access to the value in `type_with_tag`.
824  template <typename Tag, typename Tuple>
826 
827 
828  /**
829  * @brief Trait informing if there are elements in `Tuple` with tag `Tag`.
830  * @tparam Tag the sought tag
831  * @tparam Tuple the tuple-like type holding the elements to check
832  * @see `index_of_tag`, `count_tags`, `has_duplicate_tags`, `has_tag_v`
833  *
834  * Given a tuple-like type `Tuple`, this traits returns whether there is at
835  * least one element type tagged with `Tag`.
836  *
837  * For example (see above for the definitions):
838  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
839  * constexpr bool hasTagA = util::index_of_tag<TagA, Tuple_t >();
840  * constexpr bool hasTagB = util::index_of_tag<TagB, Tuple_t >();
841  * constexpr bool hasTagC = util::index_of_tag<TagC, Tuple_t >();
842  * constexpr bool hasTagD = util::index_of_tag<TagD, Tuple_t >();
843  * constexpr bool hasTagAdupl = util::index_of_tag<TagA, DuplTuple_t>();
844  * constexpr bool hasTagBdupl = util::index_of_tag<TagB, DuplTuple_t>();
845  * constexpr bool hasTagCdupl = util::index_of_tag<TagC, DuplTuple_t>();
846  * constexpr bool hasTagDdupl = util::index_of_tag<TagD, DuplTuple_t>();
847  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
848  * `hasTagA`, `hasTagB` and `hasTagC`, will be `true` and `hasTagD` will be
849  * `false`. Likewise, `hasTagAdupl` and `hasTagBdupl` will be `true`, while
850  * `hasTagCdupl` and `hasTagDdupl` will be `false`.
851  */
852  template <typename Tag, typename Tuple>
854 
855  /// Direct access to the value in `has_tag`.
856  template <typename Tag, typename Tuple>
857  constexpr bool has_tag_v = has_tag<Tag, Tuple>();
858 
859 
860  /**
861  * @brief Trait counting the elements in `Tuple` with tag `Tag`.
862  * @tparam Tag the sought tag
863  * @tparam Tuple the tuple-like type holding the elements to check
864  * @see `index_of_tag`, `count_tags_v`, `has_duplicate_tags`, `has_tag`
865  *
866  * Given a tuple-like type `Tuple`, this traits returns the number of element
867  * types tagged with `Tag`.
868  *
869  * For example (see above for the definitions):
870  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
871  * constexpr unsigned int nTagA = util::count_tags<TagA, Tuple_t >();
872  * constexpr unsigned int nTagB = util::count_tags<TagB, Tuple_t >();
873  * constexpr unsigned int nTagC = util::count_tags<TagC, Tuple_t >();
874  * constexpr unsigned int nTagD = util::count_tags<TagD, Tuple_t >();
875  * constexpr unsigned int nTagAdupl = util::count_tags<TagA, DuplTuple_t>();
876  * constexpr unsigned int nTagBdupl = util::count_tags<TagB, DuplTuple_t>();
877  * constexpr unsigned int nTagCdupl = util::count_tags<TagC, DuplTuple_t>();
878  * constexpr unsigned int nTagDdupl = util::count_tags<TagD, DuplTuple_t>();
879  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
880  * `nTagA`, `nTagB` and `nTagC`, will be `1` and `nTagD` will be `0`.
881  * Likewise, `nTagAdupl` will be `1`, `nTagBdupl` will be `2`, while
882  * `nTagCdupl` and `nTagDdupl` will be `0`.
883  */
884  template <typename Tag, typename Tuple>
886 
887  /// Direct access to the value in `count_tags`.
888  template <typename Tag, typename Tuple>
889  constexpr unsigned int count_tags_v = count_tags<Tag, Tuple>();
890 
891 
892  /**
893  * @brief Trait reporting if multiple elements in `Tuple` have the same tag.
894  * @tparam Tuple the tuple-like type holding the elements to check
895  * @see `index_of_tag`, `count_tags`, `has_duplicate_tags_v`, `has_tag`
896  *
897  * Given a tuple-like type `Tuple`, this traits returns whether any of the
898  * tags in the elements appears more than once.
899  *
900  * For example (see above for the definitions):
901  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
902  * constexpr bool hasDuplTags = util::has_duplicate_tags<Tuple_t >();
903  * constexpr bool hasDuplTagsDupl = util::has_duplicate_tags<DuplTuple_t>();
904  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
905  * `hasDuplTags`, will be `false` and `hasDuplTagsDupl` will be `true`.
906  */
907  template <typename Tuple>
909 
910  /// Direct access to the value in `has_duplicate_tags`.
911  template <typename Tuple>
913 
914 
915  /**
916  * @brief Returns the object with the specified tag.
917  * @tparam Tag the sought tag
918  * @tparam Tuple the tuple-like type holding the data
919  * @see `index_of_tag`, `count_tags`, `has_duplicate_tags`, `has_tag`
920  *
921  * This function operates in a fashion similar to `std::get()`, where instead
922  * of specifying the index or type of the object to retrieve, the tag is
923  * specified.
924  *
925  * For example (see above for the definitions):
926  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
927  * Tuple_t data(
928  * { 0, 1, 2 }, // std::vector<int> assigned to TagA
929  * { 0.5, 1.5 }, // std::vector<double> assigned to TagB
930  * "middle point" // std::string assigned to TagC
931  * );
932  * decltype(auto) TagBdata = util::getByTag<TagB>(data);
933  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
934  * `TagBdata` will be a reference to a `std::vector<double>` in `data`,
935  * currently with values `{ 0.5, 1.5 }".
936  * The attempt to use `util::getByTag()` on an argument with duplicate tags
937  * (like `DuplTuple_t`) will ensue a compilation error.
938  */
939  template <typename Tag, typename Tuple>
940  auto getByTag(Tuple const& data) -> decltype(auto)
941  { return getByExtractedType<TagExtractor, Tag>(data); }
942 
943 
944  /// @}
945 
946 } // namespace util
947 
948 
949 //------------------------------------------------------------------------------
950 //--- Template implementation
951 //------------------------------------------------------------------------------
952 namespace util {
953 
954  namespace details {
955 
956  //--------------------------------------------------------------------------
957  //
958  // CAUTION: prolonged exposition to this code may result into loss of sight.
959  //
960  //--------------------------------------------------------------------------
961  //--- implementation details (most are not documented)
962  //--------------------------------------------------------------------------
963  //--- General utilities
964  //--------------------------------------------------------------------------
965  template <typename Target, typename... T>
966  struct count_type_in_list_impl: public std::integral_constant<unsigned int, 0U>
967  {};
968 
969  template <typename Target, typename First, typename... Others>
970  struct count_type_in_list_impl<Target, First, Others...>
971  : public std::integral_constant
972  <unsigned int, count_type_in_list_impl<Target, Others...>::value>
973  {};
974 
975  template <typename Target, typename... Others>
976  struct count_type_in_list_impl<Target, Target, Others...>
977  : public std::integral_constant
978  <unsigned int, count_type_in_list_impl<Target, Others...>::value + 1>
979  {};
980 
981 
982  //--------------------------------------------------------------------------
983  //--- Courtesy traits
984  //--------------------------------------------------------------------------
985 
986 
987  //--------------------------------------------------------------------------
988  //--- Tagging
989  //--------------------------------------------------------------------------
990 
991  //--------------------------------------------------------------------------
992 
993 
994  //--------------------------------------------------------------------------
995  template <typename Target, typename... T>
996  struct type_is_in_impl: public std::false_type {};
997 
998  template <typename Target, typename First, typename... Others>
999  struct type_is_in_impl<Target, First, Others...>
1000  : public std::integral_constant<bool, type_is_in_impl<Target, Others...>::value>
1001  {};
1002 
1003  template <typename Target, typename... Others>
1004  struct type_is_in_impl<Target, Target, Others...>: public std::true_type {};
1005 
1006 
1007  //--------------------------------------------------------------------------
1008  /**
1009  * @brief Implementation for `extract_to_tuple_type`.
1010  * @tparam TargetClass as in `extract_to_tuple_type`
1011  * @tparam Extractor as in `extract_to_tuple_type`
1012  * @tparam Tuple as in `extract_to_tuple_type`
1013  * @tparam I index of the type being extracted at this iteration
1014  * @tparam N total number of types to be extracted
1015  * @tparam T types already extracted
1016  *
1017  * The recursive implementation adds the type extracted from the `I`-th
1018  * `Tuple` element to the list of T.
1019  *
1020  * The total number of iterations needs to be passed as argument since the
1021  * end-of-iteration specialization needs to define `I` as
1022  * `std::tuple_size_v<Tuple>`, but C++ (at least up to C++14) does not allow
1023  * for a typed template argument to be so complicate ().
1024  * This may change in the future,
1025  */
1026  template <template <typename...> class TargetClass, template <typename T, typename...> class Extractor, typename Tuple, std::size_t I, std::size_t N, typename... T>
1028  using type = typename extract_to_tuple_type_impl<TargetClass, Extractor, Tuple, (I + 1), N, T..., typename Extractor<std::tuple_element_t<I, Tuple>>::type>::type;
1029  }; // extract_to_tuple_type_impl
1030 
1031  /// End-of-recursion specialization: packs all types already extracted into the target type.
1032  template <template <typename...> class TargetClass, template <typename T, typename...> class Extractor, typename Tuple, std::size_t N, typename... T>
1033  struct extract_to_tuple_type_impl<TargetClass, Extractor, Tuple, N, N, T...> {
1034  using type = TargetClass<T...>;
1035  }; // extract_to_tuple_type_impl<N>
1036 
1037 
1038  //--------------------------------------------------------------------------
1039 
1040  // TODO try alternative simple implementation:
1041  template <typename SrcTuple, template <typename T, typename...> class Extractor, template <typename...> class TargetClass, std::size_t... I>
1043  using type = TargetClass<
1044  typename Extractor<std::tuple_element_t<I, SrcTuple>>::type...
1045  >;
1046  }; // extract_to_tuple_type_impl<N>
1047 
1048 
1049  //--------------------------------------------------------------------------
1050 
1051  // Part of implementation for `index_of_extracted_type`.
1052  template <template <typename T, typename...> class Extractor, typename Target, std::size_t I, typename Elem, typename Tuple>
1054 
1055  // Part of implementation for `index_of_extracted_type`.
1056  template <template <typename T, typename...> class Extractor, typename Target, std::size_t N, std::size_t I, typename Tuple>
1058  : public index_of_extracted_type_impl<Extractor, Target, I, typename Extractor<std::tuple_element_t<I, Tuple>>::type, Tuple>
1059  {};
1060 
1061  // Part of implementation for `index_of_extracted_type`.
1062  template<template <typename T, typename...> class Extractor, typename Target, std::size_t N, typename Tuple>
1063  struct index_of_extracted_type_checked<Extractor, Target, N, N, Tuple>
1064  : public std::integral_constant<std::size_t, N>
1065  {};
1066  template <template <typename T, typename...> class Extractor, typename Target, std::size_t I, typename Elem, typename Tuple>
1069  <Extractor, Target, std::tuple_size<Tuple>::value, (I + 1), Tuple>
1070  {};
1071 
1072  // Part of implementation for `index_of_extracted_type`.
1073  template <template <typename T, typename...> class Extractor, typename Target, std::size_t I, typename Tuple>
1074  struct index_of_extracted_type_impl<Extractor, Target, I, Target, Tuple>
1075  : public std::integral_constant<std::size_t, I>
1076  {
1077  static constexpr std::size_t N = std::tuple_size<Tuple>();
1078  static_assert(I < N, "Internal logic error.");
1079  };
1080 
1081  // Part of implementation for `index_of_extracted_type`.
1082  template <template <typename T, typename...> class Extractor, typename Target, std::size_t N, std::size_t After, typename Tuple>
1084  : public index_of_extracted_type_checked<Extractor, Target, N, (After + 1), Tuple>
1085  {};
1086 
1087  // Part of implementation for `index_of_extracted_type`.
1088  template <template <typename T, typename...> class Extractor, typename Target, std::size_t N, typename Tuple>
1089  struct index_of_extracted_type_checked_after<Extractor, Target, N, N, Tuple>
1090  : public std::integral_constant<std::size_t, N>
1091  {};
1092 
1093 
1094  // Part of implementation for `index_of_extracted_type`.
1095  // This implementation relies on std::tuple_size and std::tuple_element;
1096  // an implementation assuming Tuple to be std::tuple would be more efficient...
1097  template <template <typename T, typename...> class Extractor, typename Target, typename Tuple>
1099  : public std::integral_constant<
1100  std::size_t,
1101  index_of_extracted_type_checked<Extractor, Target, std::tuple_size<Tuple>::value, 0U, Tuple>::value
1102  >
1103  {};
1104 
1105  // Part of implementation for `index_of_extracted_type`.
1106  template <template <typename T, typename...> class Extractor, typename Target, typename Tuple>
1108  static constexpr std::size_t N = std::tuple_size<Tuple>::value;
1109  static constexpr std::size_t value = index_of_type_base<Extractor, Target, Tuple>();
1110 
1111  static_assert(value < N,
1112  "The specified tuple does not have the sought type.");
1114  "The specified tuple has more than one element with the sought type.");
1115  }; // struct index_of_type_helper
1116 
1117 
1118  //--------------------------------------------------------------------------
1119  // Part of implementation of `has_duplicate_types`.
1120  template <typename Tuple, typename... T>
1121  struct has_duplicate_types_impl: public std::false_type {};
1122 
1123  template <typename Tuple, typename First, typename... Others>
1124  struct has_duplicate_types_impl<Tuple, First, Others...>
1125  : public std::integral_constant<bool,
1126  (count_type_in_tuple<First, Tuple>::value > 1U)
1127  || has_duplicate_types_impl<Tuple, Others...>::value
1128  >
1129  {};
1130 
1131 
1132  // Part of implementation of `has_duplicate_types`.
1133  template <typename... T>
1134  struct has_duplicate_types_unwrapper<std::tuple<T...>>
1135  : public has_duplicate_types_impl<std::tuple<T...>, T...>
1136  {};
1137 
1138 
1139  //--------------------------------------------------------------------------
1140  // Part of implementation of `count_extracted_types` (might be exposed...).
1141  template <template <typename T, typename...> class Extractor, typename Target, typename... Tags>
1143  : public count_type_in_list<typename Extractor<Target>::type, Tags...>
1144  {};
1145 
1146  template <template <typename T, typename...> class Extractor, typename Target, typename... TagTuple>
1148 
1149  template <template <typename T, typename...> class Extractor, typename Target, typename... Tags>
1150  struct count_tags_in_tuple<Extractor, Target, std::tuple<Tags...>>
1151  : public count_type_in_tuple<typename Extractor<Target>::type, Tags...>
1152  {};
1153 
1154 
1155  //--------------------------------------------------------------------------
1156  //--- Tag traits
1157  //--------------------------------------------------------------------------
1158  template <typename Tagged, typename /* = void */>
1159  struct TagExtractorImpl {
1160  static_assert(always_false_type<Tagged>(), "This type is not tagged.");
1161  };
1162 
1163  template <typename Tagged>
1165  Tagged,
1166  std::enable_if_t
1167  <always_true_type<typename std::remove_reference_t<Tagged>::tag>::value>
1168  >
1169  {
1170  using type = typename std::remove_reference_t<Tagged>::tag;
1171  };
1172 
1173 
1174  //--------------------------------------------------------------------------
1175 
1176 
1177  } // namespace details
1178 
1179  //----------------------------------------------------------------------------
1180  //--- Implementation of the exposed traits
1181  //----------------------------------------------------------------------------
1182  //--- General utilities
1183  //----------------------------------------------------------------------------
1184  template <typename Target, typename Tuple>
1185  struct count_type_in_tuple
1186  {
1187  static_assert(always_false_type<Tuple>(),
1188  "count_type_in_tuple requires an instance of std::tuple");
1189  };
1190 
1191  // specialization: only works for std::tuples
1192  template <typename Target, typename... T>
1193  struct count_type_in_tuple<Target, std::tuple<T...>>
1194  : public count_type_in_list<Target, T...>
1195  {};
1196 
1197 
1198  //----------------------------------------------------------------------------
1199  //--- Courtesy traits
1200  //----------------------------------------------------------------------------
1201  template <
1202  typename SrcTuple,
1203  template <typename T, typename...> class Extractor,
1204  template <typename...> class TargetClass /* = std::tuple */
1205  >
1206  struct extract_to_tuple_type {
1207  private:
1208  static constexpr std::size_t N = std::tuple_size<SrcTuple>();
1209  public:
1210  using type = typename details::extract_to_tuple_type_impl
1211  <TargetClass, Extractor, SrcTuple, 0U, N>::type;
1212  }; // extract_to_tuple_type
1213 
1214 
1215  //----------------------------------------------------------------------------
1216  template<
1217  template <typename T, typename...> class Extractor,
1218  typename Target,
1219  typename Tuple
1220  >
1222  : public std::integral_constant<
1223  std::size_t,
1224  details::index_of_type_helper<Extractor, Target, Tuple>::value
1225  >
1226  {};
1227 
1228 
1229  //----------------------------------------------------------------------------
1230  template<
1231  template <typename T, typename...> class Extractor,
1232  typename Target,
1233  typename Tuple
1234  >
1235  struct has_extracted_type
1236  : public std::integral_constant<
1237  bool,
1238  (details::index_of_type_base<Extractor, Target, Tuple>::value < std::tuple_size<Tuple>::value)
1239  >
1240  {};
1241 
1242 
1243  //----------------------------------------------------------------------------
1244  template <
1245  template <typename T, typename...> class Extractor,
1246  typename Target,
1247  typename Tuple
1248  >
1249  struct count_extracted_types
1250  : public count_type_in_tuple
1251  <Target, extract_to_tuple_type_t<Tuple, Extractor>>
1252  {};
1253 
1254 
1255  //----------------------------------------------------------------------------
1256  template <
1257  template <typename T, typename...> class Extractor,
1258  typename Target,
1259  typename Tuple>
1260  auto getByExtractedType(Tuple const& data) -> decltype(auto)
1261  {
1262  using std::get;
1263  return get<index_of_extracted_type_v<Extractor, Target, Tuple>>(data);
1264  }
1265 
1266 
1267  //----------------------------------------------------------------------------
1268  //--- Tagging utilities
1269  //----------------------------------------------------------------------------
1270 
1271  //----------------------------------------------------------------------------
1272 } // namespace util
1273 
1274 
1275 //------------------------------------------------------------------------------
1276 
1277 
1278 #endif // LARDATA_UTILITIES_TUPLELOOKUPBYTAG_H
auto getByTag(Tuple const &data) -> decltype(auto)
Returns the object with the specified tag.
TaggedType(Args &&...args)
Namespace for general, non-LArSoft-specific utilities.
Counts the elements of a tuple-like type containing a Target type.
Basic C++ metaprogramming utilities.
A type with a specified tag.
typename tag_of< Tagged >::type tag_of_t
Direct access to the type in tag_of.
auto removeTag(Tagged &tagged) -> decltype(auto)
"Converts" a tagged type back to its original type.
Definition: tag.cpp:4
std::tuple_element< index_of_extracted_type_v< Extractor, Target, Tuple >, Tuple > type_with_extracted_type
Returns the element type in Tuple with the specified type.
TargetClass< typename Extractor< std::tuple_element_t< I, SrcTuple >>::type... > type
constexpr unsigned int count_tags_v
Direct access to the value in count_tags.
STL namespace.
constexpr bool type_is_in_v
Direct access to the value in type_is_in.
constexpr unsigned int count_type_in_list_v
Direct access to the value in count_type_in_list.
Holds whether the Target type is element of the specified std::tuple.
typename type_with_extracted_type< Extractor, Target, Tuple >::type type_with_extracted_type_t
Direct access to the value in type_with_extracted_type.
Extracts the tag from a type.
Tag class parametrized by a sequence of numbers.
void * Tuple
Definition: DBFolder.h:13
typename add_tag< T, Tag >::type add_tag_t
static QCString args
Definition: declinfo.cpp:674
constexpr bool has_extracted_type_v
Direct access to the value in has_extracted_type.
constexpr std::size_t index_of_tag_v
Direct access to the value in index_of_tag.
A std::false_type with a template argument.
Definition: MetaUtils.h:94
constexpr unsigned int count_extracted_types_v
Direct access to the value in count_extracted_types.
std::tuple_element< N, std::tuple< T... >> typelist_element_type
Returns the N type of the type list.
def move(depos, offset)
Definition: depos.py:107
typename remove_tag< Tagged >::type remove_tag_t
Direct access to the type contained in remove_tag.
constexpr bool has_duplicate_types_v
Direct access to the value in has_duplicate_types.
typename typelist_element_type< N, T... >::type typelist_element_t
Direct access to the value in typelist_element_type.
Trait holding the type contained in a TaggedType (or the type itself).
typename to_tuple< Tuple, TargetClass >::type to_tuple_t
Direct access to the type in to_tuple.
Trait holding whether an element in Tuple type contains Target.
typename details::extract_to_tuple_type_impl< TargetClass, Extractor, SrcTuple, 0U, N >::type type
Traits holding whether elements of Tuple have duplicate types.
constexpr bool has_type_v
Direct access to the value in has_type.
type_with_extracted_type< TagExtractor, Tag, Tuple > type_with_tag
Trait holding the type of the element of Tuple with tag Tag.
T tagged_type
Type of the object which was tagged.
Returns type TargetClass<U...> from a SrcTuple<T...>.
auto makeTagged(T &obj) -> decltype(auto)
"Converts" obj to an object with tag Tag.
Returns the index of the element in Tuple with the specified type.
typename type_with_tag< Tag, Tuple >::type type_with_tag_t
Direct access to the value in type_with_tag.
constexpr std::size_t index_of_extracted_type_v
Direct access to the value in index_of_extracted_type.
typename extract_to_tuple_type< SrcTuple, Extractor, TargetClass >::type extract_to_tuple_type_t
Direct access to the type in extract_to_tuple_type.
Implementation for extract_to_tuple_type.
static QCString type
Definition: declinfo.cpp:672
constexpr bool has_duplicate_tags_v
Direct access to the value in has_duplicate_tags.
constexpr bool has_duplicate_extracted_types_v
Direct access to the value in has_duplicate_extracted_types.
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
constexpr unsigned int count_types_v
Direct access to the value in count_extracted_types.
constexpr std::size_t index_of_type_v
Direct access to the value in index_of_type.
auto getByExtractedType(Tuple const &data) -> decltype(auto)
Returns the value of the element containing the specified type.
typename extract_tags< SrcTuple >::type extract_tags_t
Direct access to the type in extract_tags.
constexpr bool has_tag_v
Direct access to the value in has_tag.