StdUtils.h
Go to the documentation of this file.
1 /**
2  * @file larcorealg/CoreUtils/StdUtils.h
3  * @brief Functions pulling in STL customization if available.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date July , 2019
6  */
7 
8 #ifndef LARCOREALG_COREUTILS_STDUTILS_H
9 #define LARCOREALG_COREUTILS_STDUTILS_H
10 
11 // LArSoft libraries
12 #include "larcorealg/CoreUtils/MetaUtils.h" // util::is_basic_string_type_v ...
13 
14 // C/C++ standard libraries
15 #include <string> // std::to_string()
16 #include <iterator> // std::begin(), std::end(), ...
17 #include <utility> // std::get()
18 
19 
20 namespace util {
21 
22  /**
23  * @name C++ standard library customization for user-defined classes.
24  * @defgroup LArSoft_CoreUtils_StdUtils C++ STL customizations
25  *
26  * There are a number of functions that are provided by C++ standard library
27  * for the data types and classes defined in the standard.
28  * It is often desirable to have your class react to these standard functions
29  * in a standard way, for example for a container to react to `std::begin()`
30  * to return its `begin()` iterator. While sometimes this is easy (for example
31  * `std::begin()` calls `begin()` member function if available), some other
32  * times that is not possible. In that case, since overloading of functions in
33  * the `std` namespace is not allowed by C++, the usual pattern is to rely on
34  * the argument-dependent lookup (known as "ADL") to have the comnpiler find
35  * the overloaded function that is defined in the same namespace as any of
36  * the arguments. For example:
37  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
38  * userns::MyObj obj;
39  * // ...
40  * using std::to_string;
41  * std::string objstr = to_string(obj);
42  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43  * will look in the namespace where the type of `obj` is defined (that is
44  * `userns`) for a `userns::to_string`, then will consider `std::to_string`
45  * it self.
46  *
47  * The utilities provided here provide a transparent way to do that, at the
48  * cost of a new header and some non-standard call. The equivalent call of the
49  * above would be:
50  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
51  * userns::MyObj obj;
52  * // ...
53  * std::string objstr = util::to_string(obj);
54  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
55  *
56  * @note For customization of templates, like `std::hash` or
57  * `std::numeric_limits`, specialization of classes in `std` is allowed
58  * by the standard, so no particular trick is required.
59  */
60  /// @{
61 
62 
63  /// ADL-aware version of `std::to_string`.
64  template <typename T>
65  constexpr decltype(auto) to_string(T&& obj);
66 // { using std::to_string; return to_string(std::forward<T>(obj)); }
67 
68 
69  // --- BEGIN --- Containers and iterators ------------------------------------
70  /// ADL-aware version of `std::begin`.
71  template <typename T>
72  constexpr decltype(auto) begin(T&& obj)
73  { using std::begin; return begin(std::forward<T>(obj)); }
74 
75  /// ADL-aware version of `std::end`.
76  template <typename T>
77  constexpr decltype(auto) end(T&& obj)
78  { using std::end; return end(std::forward<T>(obj)); }
79 
80  /// ADL-aware version of `std::cbegin`.
81  template <typename T>
82  constexpr decltype(auto) cbegin(T&& obj)
83  { using std::cbegin; return cbegin(std::forward<T>(obj)); }
84 
85  /// ADL-aware version of `std::cend`.
86  template <typename T>
87  constexpr decltype(auto) cend(T&& obj)
88  { using std::cend; return cend(std::forward<T>(obj)); }
89 
90  /// ADL-aware version of `std::size`.
91  template <typename T>
92  constexpr decltype(auto) size(T&& obj)
93  { using std::size; return size(std::forward<T>(obj)); }
94 
95  /// ADL-aware version of `std::empty`.
96  template <typename T>
97  constexpr decltype(auto) empty(T&& obj)
98  { using std::empty; return empty(std::forward<T>(obj)); }
99 
100  // --- END --- Containers and iterators --------------------------------------
101 
102 
103 
104  // --- BEGIN --- tuples ------------------------------------------------------
105 
106  template <std::size_t I, typename T>
107  decltype(auto) get(T&& obj)
108  { using std::get; return get<I>(std::forward<T>(obj)); }
109 
110  // --- END --- tuples --------------------------------------------------------
111 
112  /// @}
113 
114 
115 } // namespace util
116 
117 // -----------------------------------------------------------------------------
118 // --- template implementation
119 // -----------------------------------------------------------------------------
120 namespace util::details {
121 
122  // ---------------------------------------------------------------------------
123  template <typename T, typename = void>
124  struct ToStringImpl {
125 
126  template <typename U>
127  static std::string to_string(U&& obj)
128  { using std::to_string; return to_string(std::forward<U>(obj)); }
129 
130  }; // struct ToStringImpl
131 
132 
133  // ---------------------------------------------------------------------------
134  template <typename T>
135  struct ToStringImpl<T, std::enable_if_t<util::is_basic_string_type_v<T>>> {
136 
137  template <typename U>
138  static std::string to_string(U&& obj) { return obj; }
139 
140  }; // struct ToStringImpl<string>
141 
142 
143  // ---------------------------------------------------------------------------
144  template <typename T>
145  struct ToStringImpl<T, std::enable_if_t<util::is_basic_string_view_type_v<T>>>
146  {
147 
148  template <typename U>
149  static std::string to_string(U&& obj) { return { obj.begin(), obj.end() }; }
150 
151  }; // struct ToStringImpl<string_view>
152 
153 
154  // ---------------------------------------------------------------------------
155 
156 } // namespace util::details
157 
158 
159 // -----------------------------------------------------------------------------
160 template <typename T>
161 constexpr decltype(auto) util::to_string(T&& obj)
162  { return util::details::ToStringImpl<T>::to_string(std::forward<T>(obj)); }
163 // { using std::to_string; return to_string(std::forward<T>(obj)); }
164 
165 
166 // -----------------------------------------------------------------------------
167 
168 #endif // LARCOREALG_COREUTILS_STDUTILS_H
169 
Namespace for general, non-LArSoft-specific utilities.
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
Basic C++ metaprogramming utilities.
std::string string
Definition: nybbler.cc:12
STL namespace.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
decltype(auto) constexpr to_string(T &&obj)
ADL-aware version of std::to_string.
static std::string to_string(U &&obj)
Definition: StdUtils.h:127
decltype(auto) get(T &&obj)
Definition: StdUtils.h:107
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:82
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97