OpenKalman
movable_wrapper.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2025 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
17 #ifndef OPENKALMAN_MOVABLE_WRAPPER_HPP
18 #define OPENKALMAN_MOVABLE_WRAPPER_HPP
19 
20 #include <functional>
21 #include "basics/basics.hpp"
22 
24 {
31  template<typename T>
32 #ifdef __cpp_concepts
33  requires (std::move_constructible<T> and std::is_object_v<T>) or std::is_lvalue_reference_v<T>
34 #endif
36  {
37  private:
38 
39  static_assert(stdex::move_constructible<T> and std::is_object_v<T>);
40 
42 
43  public:
44 
48  using type = T;
49 
50 
54  constexpr
55 #ifdef __cpp_lib_concepts
56  movable_wrapper() noexcept(std::is_nothrow_default_constructible_v<T_>) requires std::default_initializable<T_> = default;
57 #else
58  movable_wrapper() noexcept(std::is_nothrow_default_constructible_v<T_>) = default;
59 #endif
60 
61 
65  explicit constexpr
66  movable_wrapper(T&& t) : t_ {std::move(t)} {}
67 
68 
72  constexpr T& get() & noexcept { return t_.operator*(); }
74  constexpr const T& get() const & noexcept { return t_.operator*(); }
76  constexpr T&& get() && noexcept { return std::move(t_.operator*()); }
78  constexpr const T&& get() const && noexcept { return std::move(t_.operator*()); }
79 
80 
84  constexpr operator T& () & noexcept { return t_.operator*(); }
86  constexpr operator const T& () const & noexcept { return t_.operator*(); }
88  constexpr operator T () && noexcept { return std::move(t_.operator*()); }
90  constexpr operator const T () const && noexcept { return std::move(t_.operator*()); }
91 
92 
96  template<typename...ArgTypes>
97  constexpr std::invoke_result_t<T&, ArgTypes...>
98  operator () (ArgTypes&&...args) & noexcept(std::is_nothrow_invocable_v<T&, ArgTypes...>)
99  {
100  return stdex::invoke(t_.operator*(), std::forward<ArgTypes>(args)...);
101  }
102 
104  template<typename...ArgTypes>
105  std::invoke_result_t<const T&, ArgTypes...>
106  constexpr operator () (ArgTypes&&...args) const & noexcept(std::is_nothrow_invocable_v<const T&, ArgTypes...>)
107  {
108  return stdex::invoke(t_.operator*(), std::forward<ArgTypes>(args)...);
109  }
110 
112  template<typename...ArgTypes>
113  std::invoke_result_t<T&&, ArgTypes...>
114  constexpr operator () (ArgTypes&&...args) && noexcept(std::is_nothrow_invocable_v<T&&, ArgTypes...>)
115  {
116  return stdex::invoke(std::move(t_.operator*()), std::forward<ArgTypes>(args)...);
117  }
118 
120  template<typename...ArgTypes>
121  std::invoke_result_t<const T&&, ArgTypes...>
122  constexpr operator () (ArgTypes&&...args) const && noexcept(std::is_nothrow_invocable_v<const T&&, ArgTypes...>)
123  {
124  return stdex::invoke(std::move(t_.operator*()), std::forward<ArgTypes>(args)...);
125  }
126 
127  private:
128 
129  T_ t_;
130 
131  };
132 
133 
139  template<typename T>
140  struct movable_wrapper<T&>
141  {
142  private:
143 
145 
146  public:
147 
151  using type = T&;
152 
153 
157  explicit constexpr
158  movable_wrapper(T& t) : t_ {t} {}
159 
160 
164  constexpr T& get() const noexcept { return t_; }
165 
166 
170  constexpr operator T& () const noexcept { return t_; }
171 
172 
176  template<typename...ArgTypes>
177  constexpr std::invoke_result_t<T&, ArgTypes...>
178  operator () (ArgTypes&&...args) const noexcept(std::is_nothrow_invocable_v<T&, ArgTypes...>)
179  {
180  return stdex::invoke(t_, std::forward<ArgTypes>(args)...);
181  }
182 
183  private:
184 
185  T_ t_;
186 
187  };
188 
189 
193  template<typename T>
195 
196 
197 
198 #ifdef __cpp_impl_three_way_comparison
199  template<typename T>
200  constexpr bool operator==(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
201  requires requires { {lhs.get() == rhs.get()} -> OpenKalman::internal::boolean_testable; }
202  {
203  return lhs.get() == rhs.get();
204  }
205 
206  template<typename T>
207  constexpr bool operator==(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
208  requires (not std::is_const_v<T>) and requires { {lhs.get() == rhs.get()} -> OpenKalman::internal::boolean_testable; }
209  {
210  return lhs.get() == rhs.get();
211  }
212 
213  template<typename T>
214  constexpr bool operator==(const movable_wrapper<T>& lhs, const T& ref) noexcept
215  requires requires { {lhs.get() == ref} -> OpenKalman::internal::boolean_testable; }
216  {
217  return lhs.get() == ref;
218  }
219 
220  template<typename T>
221  constexpr auto operator<=>(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
222  requires requires {
223  {lhs.get() < rhs.get()} -> OpenKalman::internal::boolean_testable;
224  {lhs.get() > rhs.get()} -> OpenKalman::internal::boolean_testable; }
225  {
226  return lhs.get() <=> rhs.get();
227  }
228 
229  template<typename T>
230  constexpr auto operator<=>(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept requires
231  (not std::is_const_v<T>) and
232  requires {
233  {lhs.get() < rhs.get()} -> OpenKalman::internal::boolean_testable;
234  {lhs.get() > rhs.get()} -> OpenKalman::internal::boolean_testable; }
235  {
236  return lhs.get() <=> rhs.get();
237  }
238 
239  template<typename T>
240  constexpr auto operator<=>(const movable_wrapper<T>& lhs, const T& ref) noexcept
241  requires requires {
242  {lhs.get() < ref} -> OpenKalman::internal::boolean_testable;
243  {lhs.get() > ref} -> OpenKalman::internal::boolean_testable; }
244  {
245  return lhs.get() <=> ref;
246  }
247 #else
248  template<typename T, std::enable_if_t<
249  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<const movable_wrapper<T>&>().get())>, int> = 0>
250  constexpr bool operator==(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
251  { return lhs.get() == rhs.get(); }
252 
253  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
254  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<movable_wrapper<T>&>().get())>, int> = 0>
255  constexpr bool operator==(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
256  { return lhs.get() == rhs.get(); }
257 
258  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
259  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() == std::declval<movable_wrapper<T>&>().get())>, int> = 0>
260  constexpr bool operator==(const movable_wrapper<const T>& lhs, const movable_wrapper<T>& rhs) noexcept
261  { return lhs.get() == rhs.get(); }
262 
263  template<typename T, std::enable_if_t<
264  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() == std::declval<const T&>())>, int> = 0>
265  constexpr bool operator==(const movable_wrapper<T>& lhs, const T& ref) noexcept
266  { return lhs.get() == ref; }
267 
268  template<typename T, std::enable_if_t<
269  OpenKalman::internal::boolean_testable<decltype(std::declval<const T&>() == std::declval<movable_wrapper<T>&>().get())>, int> = 0>
270  constexpr bool operator==(const T& ref, const movable_wrapper<T>& lhs) noexcept
271  { return ref == lhs.get(); }
272 
273 
274  template<typename T, std::enable_if_t<
275  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<const movable_wrapper<T>&>().get())>, int> = 0>
276  constexpr bool operator!=(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
277  { return lhs.get() != rhs.get(); }
278 
279  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
280  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() != std::declval<movable_wrapper<T>&>().get())>, int> = 0>
281  constexpr bool operator!=(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
282  { return lhs.get() != rhs.get(); }
283 
284  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
285  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() != std::declval<movable_wrapper<T>&>().get())>, int> = 0>
286  constexpr bool operator!=(const movable_wrapper<const T>& lhs, const movable_wrapper<T>& rhs) noexcept
287  { return lhs.get() != rhs.get(); }
288 
289  template<typename T, std::enable_if_t<
290  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() != std::declval<const T&>())>, int> = 0>
291  constexpr bool operator!=(const movable_wrapper<T>& lhs, const T& ref) noexcept
292  { return lhs.get() != ref; }
293 
294  template<typename T, std::enable_if_t<
295  OpenKalman::internal::boolean_testable<decltype(std::declval<const T&>() != std::declval<movable_wrapper<T>&>().get())>, int> = 0>
296  constexpr bool operator!=(const T& ref, const movable_wrapper<T>& lhs) noexcept
297  { return ref != lhs.get(); }
298 
299 
300 template<typename T, std::enable_if_t<
301  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<const movable_wrapper<T>&>().get())>, int> = 0>
302 constexpr bool operator<(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
303  { return lhs.get() < rhs.get(); }
304 
305  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
306  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() < std::declval<movable_wrapper<T>&>().get())>, int> = 0>
307  constexpr bool operator<(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
308  { return lhs.get() < rhs.get(); }
309 
310  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
311  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() < std::declval<movable_wrapper<T>&>().get())>, int> = 0>
312  constexpr bool operator<(const movable_wrapper<const T>& lhs, const movable_wrapper<T>& rhs) noexcept
313  { return lhs.get() < rhs.get(); }
314 
315  template<typename T, std::enable_if_t<
316  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() < std::declval<const T&>())>, int> = 0>
317  constexpr bool operator<(const movable_wrapper<T>& lhs, const T& ref) noexcept
318  { return lhs.get() < ref; }
319 
320  template<typename T, std::enable_if_t<
321  OpenKalman::internal::boolean_testable<decltype(std::declval<const T&>() < std::declval<movable_wrapper<T>&>().get())>, int> = 0>
322  constexpr bool operator<(const T& ref, const movable_wrapper<T>& lhs) noexcept
323  { return ref < lhs.get(); }
324 
325 
326 template<typename T, std::enable_if_t<
327  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<const movable_wrapper<T>&>().get())>, int> = 0>
328 constexpr bool operator>(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
329  { return lhs.get() > rhs.get(); }
330 
331  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
332  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() > std::declval<movable_wrapper<T>&>().get())>, int> = 0>
333  constexpr bool operator>(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
334  { return lhs.get() > rhs.get(); }
335 
336  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
337  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() > std::declval<movable_wrapper<T>&>().get())>, int> = 0>
338  constexpr bool operator>(const movable_wrapper<const T>& lhs, const movable_wrapper<T>& rhs) noexcept
339  { return lhs.get() > rhs.get(); }
340 
341  template<typename T, std::enable_if_t<
342  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() > std::declval<const T&>())>, int> = 0>
343  constexpr bool operator>(const movable_wrapper<T>& lhs, const T& ref) noexcept
344  { return lhs.get() > ref; }
345 
346  template<typename T, std::enable_if_t<
347  OpenKalman::internal::boolean_testable<decltype(std::declval<const T&>() > std::declval<movable_wrapper<T>&>().get())>, int> = 0>
348  constexpr bool operator>(const T& ref, const movable_wrapper<T>& lhs) noexcept
349  { return ref > lhs.get(); }
350 
351 
352 template<typename T, std::enable_if_t<
353  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<const movable_wrapper<T>&>().get())>, int> = 0>
354 constexpr bool operator<=(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
355  { return lhs.get() <= rhs.get(); }
356 
357  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
358  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() <= std::declval<movable_wrapper<T>&>().get())>, int> = 0>
359  constexpr bool operator<=(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
360  { return lhs.get() <= rhs.get(); }
361 
362  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
363  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() <= std::declval<movable_wrapper<T>&>().get())>, int> = 0>
364  constexpr bool operator<=(const movable_wrapper<const T>& lhs, const movable_wrapper<T>& rhs) noexcept
365  { return lhs.get() <= rhs.get(); }
366 
367  template<typename T, std::enable_if_t<
368  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() <= std::declval<const T&>())>, int> = 0>
369  constexpr bool operator<=(const movable_wrapper<T>& lhs, const T& ref) noexcept
370  { return lhs.get() <= ref; }
371 
372  template<typename T, std::enable_if_t<
373  OpenKalman::internal::boolean_testable<decltype(std::declval<const T&>() <= std::declval<movable_wrapper<T>&>().get())>, int> = 0>
374  constexpr bool operator<=(const T& ref, const movable_wrapper<T>& lhs) noexcept
375  { return ref <= lhs.get(); }
376 
377 
378 template<typename T, std::enable_if_t<
379  OpenKalman::internal::boolean_testable<decltype(std::declval<const movable_wrapper<T>&>().get() == std::declval<const movable_wrapper<T>&>().get())>, int> = 0>
380 constexpr bool operator>=(const movable_wrapper<T>& lhs, const movable_wrapper<T>& rhs) noexcept
381  { return lhs.get() >= rhs.get(); }
382 
383  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
384  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() >= std::declval<movable_wrapper<T>&>().get())>, int> = 0>
385  constexpr bool operator>=(const movable_wrapper<T>& lhs, const movable_wrapper<const T>& rhs) noexcept
386  { return lhs.get() >= rhs.get(); }
387 
388  template<typename T, std::enable_if_t<(not std::is_const_v<T>) and
389  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() >= std::declval<movable_wrapper<T>&>().get())>, int> = 0>
390  constexpr bool operator>=(const movable_wrapper<const T>& lhs, const movable_wrapper<T>& rhs) noexcept
391  { return lhs.get() >= rhs.get(); }
392 
393  template<typename T, std::enable_if_t<
394  OpenKalman::internal::boolean_testable<decltype(std::declval<movable_wrapper<T>&>().get() >= std::declval<const T&>())>, int> = 0>
395  constexpr bool operator>=(const movable_wrapper<T>& lhs, const T& ref) noexcept
396  { return lhs.get() >= ref; }
397 
398  template<typename T, std::enable_if_t<
399  OpenKalman::internal::boolean_testable<decltype(std::declval<const T&>() >= std::declval<movable_wrapper<T>&>().get())>, int> = 0>
400  constexpr bool operator>=(const T& ref, const movable_wrapper<T>& lhs) noexcept
401  { return ref >= lhs.get(); }
402 #endif
403 
404 
405 #if __cplusplus >= 202002L
406  namespace detail
407  {
408  template <class T>
409  inline constexpr bool is_movable_wrapper_ref = false;
410 
411  template <class T>
412  inline constexpr bool is_movable_wrapper_ref<movable_wrapper<T&>> = true;
413  }
414 
415 
416  template<typename R, typename T, typename RQ, typename TQ>
417  concept movable_wrapper_common_reference_exists_with =
418  detail::is_movable_wrapper_ref<R> and
419  requires { typename stdex::common_reference_t<typename R::type, TQ>; } and
420  std::convertible_to<RQ, stdex::common_reference_t<typename R::type, TQ>>
421  ;
422 #endif
423 
424 }
425 
426 
427 namespace std
428 {
429 #if __cplusplus >= 202002L
430  template <typename R, typename T, template<typename> typename RQual, template<typename> typename TQual> requires
431  OpenKalman::collections::internal::movable_wrapper_common_reference_exists_with<R, T, RQual<R>, TQual<T>> and
432  (not OpenKalman::collections::internal::movable_wrapper_common_reference_exists_with<T, R, TQual<T>, RQual<R>>)
433  struct basic_common_reference<R, T, RQual, TQual>
434  {
435  using type = common_reference_t<typename R::type, TQual<T>>;
436  };
437 
438 
439  template <typename T, typename R, template <typename> typename TQual, template <typename> typename RQual> requires
440  OpenKalman::collections::internal::movable_wrapper_common_reference_exists_with<R, T, RQual<R>, TQual<T>> and
441  (not OpenKalman::collections::internal::movable_wrapper_common_reference_exists_with<T, R, TQual<T>, RQual<R>>)
442  struct basic_common_reference<T, R, TQual, RQual>
443  {
444  using type = common_reference_t<typename R::type, TQual<T>>;
445  };
446 #endif
447 
448 
449 }
450 
451 #endif
constexpr movable_wrapper(T &&t)
Construct from an rvalue reference.
Definition: movable_wrapper.hpp:66
constexpr movable_wrapper() noexcept(std::is_nothrow_default_constructible_v< T_ >)=default
Default constructor.
F type
The wrapped type.
Definition: movable_wrapper.hpp:48
constexpr std::invoke_result_t< T &, ArgTypes... > operator()(ArgTypes &&...args) &noexcept(std::is_nothrow_invocable_v< T &, ArgTypes... >)
Call the wrapped object if it is callable.
Definition: movable_wrapper.hpp:98
constexpr T & get() &noexcept
Retrieve the stored value.
Definition: movable_wrapper.hpp:72
constexpr movable_wrapper(T &t)
Construct from an lvalue reference.
Definition: movable_wrapper.hpp:158
Definition: tuple_like_to_tuple.hpp:24
Basic definitions for OpenKalman as a whole.
T & type
The wrapped type.
Definition: movable_wrapper.hpp:151
Definition: movable_wrapper.hpp:35