Dereference.h
Go to the documentation of this file.
1 /**
2  * @brief Functor to dereference an object if the object is a pointer
3  * @author Gianluca Petrillo (petrillo@fnal.gov)
4  * @date January 23rd, 2015
5  *
6  */
7 
8 #ifndef LARDATA_UTILITIES_DEREFERENCE_H
9 #define LARDATA_UTILITIES_DEREFERENCE_H 1
10 
11 // C/C++ standard libraries
12 #include <type_traits>
13 
14 /// LArSoft namespace
15 namespace lar {
16  /// LArSoft utilities namespace
17  namespace util {
18  /// Implementation of utility details
19  namespace details {
20 
21 
22  /// Class compiling only if type T exists (then, it's std::true_type)
23  template <typename T>
24  struct is_type: public std::true_type {};
25 
26 
27  //@{
28  /**
29  * @brief Class defining whether the specified type can be dereferenced
30  * @tparam T the type to be tested for dereferenciation
31  * @tparam Enable triggers the conditional compilation
32  *
33  * Usage:
34  *
35  * static_assert(!has_dereference_class<int>::value, "error");
36  * static_assert(has_dereference_class<int*>::value, "error");
37  *
38  *
39  * Implementation details
40  * -----------------------
41  *
42  * The class is implemented by two definitions:
43  * 1. a general one, always equivalent to std::false_type
44  * 2. a special one, always equivalent to std::true_type, defined only
45  * if the type T can be dereferenced (that is, if *(T()) is valid)
46  *
47  * The selection mechanism will always select the second form if
48  * available, since it is more specialized.
49  */
50  template <typename T, typename Enable = void>
51  struct has_dereference_class: public std::false_type {};
52 
53  template <typename T>
55  T,
56  typename std::enable_if<is_type<decltype(*(T()))>::value, void>::type
57  >:
58  public std::true_type
59  {};
60  //@}
61 
62 
63  //@{
64  /**
65  * @brief Class holding the type dereferenced from an object of type T
66  * @tparam T the type to be tested
67  * @tparam CanDereference whether T can be dereferenced or not
68  * @see lar::util::dereferenced_type
69  *
70  * This class can be used as:
71  *
72  * static_assert(std::is_same<
73  * typename dereferenced_type<int, false>::type,
74  * int
75  * >::value,
76  * "error");
77  * static_assert(std::is_same<
78  * typename dereferenced_type<int*, true>::type,
79  * int&
80  * >::value,
81  * "error");
82  *
83  * The type is contained in the `type` member of the class.
84  * The `type` is precisely what is obtained by dereferencing T (that is
85  * often a reference to a type).
86  * Note that the second parameter must express correctly whether the first
87  * type can be dereferenced or not. Clearly, this class is not very useful
88  * by itself, since we have to tell it how to do the trick
89  * (lar::util::dereferenced_type puts everything together).
90  * It is used in association with has_dereference_class.
91  *
92  * The implementation is the usual two-definition one:
93  * 1. generic class, always with the same type T
94  * (that we associate with CanDereference false)
95  * 2. specialized class, with CanDereference explicitly set to true,
96  * that has the type *T
97  *
98  */
99  template <typename T, bool CanDereference>
101  // using type = typename std::add_lvalue_reference<T>::type;
102  using type = T;
103  }; // dereferenced_type <>
104 
105  template <typename T>
106  struct dereferenced_type<T, true> {
107  using type = decltype(*T());
108  }; // dereferenced_type<T, true>
109  //@}
110 
111 
112 
113  //@{
114  /**
115  * @brief Functor returning the dereferenced value of the argument
116  * @tparam T type of the argument
117  * @tparam CanDereference whether T can be dereferenced or not
118  *
119  * The functor defines a call operator returning:
120  * 1. a reference to the value pointed by the argument (CanDereference)
121  * 2. or, a reference to the argument itself (!CanDereference).
122  *
123  * The behaviour is therefore determined by the CanDereference parameter.
124  * Note that the second parameter must express correctly whether the first
125  * type can be dereferenced or not. Clearly, this class is not very useful
126  * by itself, since we have to tell it how to do the trick.
127  * It is used in association with has_dereference_class.
128  *
129  * This class is state-less.
130  */
131  template <typename T, bool CanDereference>
133  using argument_type = T;
134  using reference_type = typename std::add_lvalue_reference
136 
137  reference_type operator() (argument_type& ref) const { return ref; }
138  }; // dereference_class<T, bool>
139 
140 
141  template <typename T>
142  struct dereference_class<T, true> {
143  using argument_type = T;
144  using reference_type = typename std::add_lvalue_reference
146 
147  reference_type operator() (argument_type& ref) const { return *ref; }
148  }; // dereference_class<T, true>
149  //@}
150 
151 
152  //@{
153  /**
154  * @brief Functor returning the pointer to a value in the argument
155  * @tparam T type of the argument
156  * @tparam CanDereference whether T can be dereferenced or not
157  *
158  * The functor defines a call operator returning:
159  * 1. a pointer to the value pointed by the argument (CanDereference), or
160  * 2. a pointer to the argument itself (!CanDereference).
161  *
162  * The behaviour is therefore determined by the CanDereference parameter.
163  * Note that the second parameter must express correctly whether the first
164  * type can be dereferenced or not. Clearly, this class is not very useful
165  * by itself, since we have to tell it how to do the trick.
166  * It is used in association with has_dereference_class.
167  *
168  * This class is state-less.
169  */
170  template <typename T, bool CanDereference>
172  using argument_type = T;
173  using pointer_type = typename std::add_pointer
175 
176  pointer_type operator() (argument_type& ref) const { return &ref; }
177  }; // make_pointer_class<T, bool>
178 
179 
180  template <typename T>
181  struct make_pointer_class<T, true> {
182  using argument_type = T;
183  using pointer_type = typename std::add_pointer
185 
186  pointer_type operator() (argument_type& ref) const { return &*ref; }
187  }; // make_pointer_class<T, true>
188  //@}
189 
190  } // namespace details
191 
192 
193  /** ************************************************************************
194  * @brief Class defining the dereferenced type of the specified type
195  * @tparam T the type to be tested for dereferenciation
196  *
197  * Usage:
198  *
199  * static_assert(
200  * std::is_same<typename lar::util::dereferenced_type<int>::type, int>,
201  * "error"
202  * );
203  * static_assert(
204  * std::is_same<typename lar::util::dereferenced_type<int*>::type, int&>,
205  * "error"
206  * );
207  *
208  * The type is contained in the `type` member of the class.
209  * The `type` is precisely what is obtained by dereferencing T (that is
210  * often a reference to a type).
211  *
212  * The interaction with const `T` types and with constant dereference
213  * operators (`T::operator* () const`) has not been investigated.
214  */
215  template <typename T>
216  struct dereferenced_type: public
217  details::dereferenced_type<T, details::has_dereference_class<T>::value>
218  {};
219 
220 
221  /** ************************************************************************
222  * @brief Returns the value pointed by the argument, or the argument itself
223  * @tparam T the type of the argument
224  * @param v the value to be dereferenced
225  * @return the value v points to, if any, or v itself
226  *
227  * This function allows the use of the same template code to process both
228  * pointers and pointed values.
229  * For example:
230  *
231  * template <typename T>
232  * std::vector<int> extract_int(std::vector<T> const& from) {
233  * std::vector<int> v;
234  * v.reserve(from.size());
235  * std::transform(from.begin(), from.end(), std::back_inserter(v),
236  * util::dereference);
237  * return v;
238  * }
239  *
240  * int value = 10;
241  * std::vector<int> v(10, value);
242  * std::vector<int*> v_ptr(10, &value);
243  *
244  * extract_int(v);
245  * extract_int(v_ptr);
246  *
247  * shows that the same function can be used on vectors of integers and of
248  * their pointers.
249  */
250  template <typename T>
251  inline
255  {
258  }
259 
260  /** ************************************************************************
261  * @brief Returns a pointer to the value of argument, or the argument itself
262  * @tparam T the type of the argument
263  * @param v the value to be taken the pointer of
264  * @return a pointer to v, or v itself if it is already a C pointer
265  *
266  * This function allows the use of the same template code to process both
267  * pointers and pointed values.
268  * For example:
269  *
270  * template <typename T>
271  * std::vector<int*> extract_int(std::vector<T> const& from) {
272  * std::vector<int*> v;
273  * v.reserve(from.size());
274  * std::transform(from.begin(), from.end(), std::back_inserter(v),
275  * util::make_pointer);
276  * return v;
277  * }
278  *
279  * int value = 10;
280  * std::vector<int> v(10, value);
281  * std::vector<int*> v_ptr(10, &value);
282  *
283  * extract_int(v);
284  * extract_int(v_ptr);
285  *
286  * shows that the same function can be used on vectors of integers and of
287  * their pointers.
288  */
289  template <typename T>
290  inline
294  {
297  }
298 
299  } // namespace util
300 
301 } // namespace lar
302 
303 #endif // LARDATA_UTILITIES_DEREFERENCE_H
Functor returning the dereferenced value of the argument.
Definition: Dereference.h:132
Namespace for general, non-LArSoft-specific utilities.
details::make_pointer_class< T, details::has_dereference_class< T >::value >::pointer_type make_pointer(T &v)
Returns a pointer to the value of argument, or the argument itself.
Definition: Dereference.h:293
typename std::add_lvalue_reference< typename dereferenced_type< T, CanDereference >::type >::type reference_type
Definition: Dereference.h:135
typename std::add_lvalue_reference< typename dereferenced_type< T, true >::type >::type reference_type
Definition: Dereference.h:145
STL namespace.
Functor returning the pointer to a value in the argument.
Definition: Dereference.h:171
typename std::add_pointer< typename dereferenced_type< T, CanDereference >::type >::type pointer_type
Definition: Dereference.h:174
typename std::add_pointer< typename dereferenced_type< T, true >::type >::type pointer_type
Definition: Dereference.h:184
details::dereference_class< T, details::has_dereference_class< T >::value >::reference_type dereference(T &v)
Returns the value pointed by the argument, or the argument itself.
Definition: Dereference.h:254
Class defining the dereferenced type of the specified type.
Definition: Dereference.h:216
LArSoft-specific namespace.
Class holding the type dereferenced from an object of type T.
Definition: Dereference.h:100
static QCString type
Definition: declinfo.cpp:672
Class compiling only if type T exists (then, it&#39;s std::true_type)
Definition: Dereference.h:24
Class defining whether the specified type can be dereferenced.
Definition: Dereference.h:51