packio
movable_function.h
1 // This Source Code Form is subject to the terms of the Mozilla Public
2 // License, v. 2.0. If a copy of the MPL was not distributed with this
3 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4 
5 #ifndef PACKIO_UNIQUE_FUNCTION_H
6 #define PACKIO_UNIQUE_FUNCTION_H
7 
8 #include <functional>
9 #include <type_traits>
10 #include <utility>
11 
12 namespace packio {
13 namespace internal {
14 
15 template <typename T>
16 class movable_function : public std::function<T> {
17  template <typename Fn, typename En = void>
18  struct wrapper {
19  };
20 
21  // specialization for CopyConstructible Fn
22  template <typename Fn>
23  struct wrapper<Fn, std::enable_if_t<std::is_copy_constructible<Fn>::value>> {
24  Fn fn;
25 
26  template <typename... Args>
27  auto operator()(Args&&... args)
28  {
29  return fn(std::forward<Args>(args)...);
30  }
31  };
32 
33  // specialization for MoveConstructible-only Fn
34  template <typename Fn>
35  struct wrapper<
36  Fn,
37  std::enable_if_t<
38  !std::is_copy_constructible<Fn>::value
39  && std::is_move_constructible<Fn>::value>> {
40  Fn fn;
41 
42  wrapper(Fn&& fn) : fn(std::forward<Fn>(fn)) {}
43 
44  wrapper(wrapper&&) = default;
45  wrapper& operator=(wrapper&&) = default;
46 
47  // these two functions are instantiated by std::function and are never called
48  wrapper(const wrapper& rhs) : fn(const_cast<Fn&&>(rhs.fn))
49  {
50  // hack to initialize fn for non-DefaultContructible types
51  std::abort();
52  }
53  wrapper& operator=(wrapper&) { std::abort(); }
54 
55  template <typename... Args>
56  auto operator()(Args&&... args)
57  {
58  return fn(std::forward<Args>(args)...);
59  }
60  };
61 
62  using base = std::function<T>;
63 
64 public:
65  movable_function() noexcept = default;
66  movable_function(std::nullptr_t) noexcept : base(nullptr) {}
67 
68  template <typename Fn>
69  movable_function(Fn&& f) : base(wrapper<Fn>{std::forward<Fn>(f)})
70  {
71  }
72 
73  movable_function(movable_function&&) = default;
74  movable_function& operator=(movable_function&&) = default;
75 
76  movable_function& operator=(std::nullptr_t)
77  {
78  base::operator=(nullptr);
79  return *this;
80  }
81 
82  template <typename Fn>
83  movable_function& operator=(Fn&& f)
84  {
85  base::operator=(wrapper<Fn>{std::forward<Fn>(f)});
86  return *this;
87  }
88 
89  using base::operator();
90 };
91 
92 } // internal
93 } // packio
94 
95 #endif // PACKIO_UNIQUE_FUNCTION_H
The packio namespace.
Definition: arg.h:14