Ticket #13114: function.hpp

File function.hpp, 4.6 KB (added by stinkingmadgod@…, 5 years ago)

Proof-of-concept for function taking multiple signatures

Line 
1#ifndef FUNCTION_HPP_INCLUDED
2#define FUNCTION_HPP_INCLUDED
3
4/*
5 function is a buffed duplicate of std::function, but can have arbitrary amounts of signatures
6
7 function<void (int), double (char*, float&)> f; // wow!
8
9 Differences:
10
11 Doesn't have "target access" whatever that means, mainly because I didn't find a use
12 for that my entire life using std::function.
13
14 Doesn't support allocator stuff, they're deprecated in C++17 anyways.
15
16 Note:
17
18 When the function is invoked, overload resolution is performed
19
20 function<void (char), void (double)> f = [](auto x){cout << sizeof(x) << endl;};
21 f('c'); // prints 1
22 f(4.2); // prints sizeof(double), likely 8
23
24 It is thus valid to construct a function with an object that doesn't have the exact
25 signature as specified as long as there is an implicit conversion from the specified
26 signature to the object's operator()
27
28 function<void (int), void (double)> f = [](int i){cout << i << endl;};
29 f(42.5); // prints 42, due to double to int conversion
30 f(420); // prints 420
31
32 Remember the return types can vary
33
34 function<int* (), pair<int, int> (int), double (char, char)> f = something;
35 int* p = f();
36 auto [x, y] = f(4200);
37 double d = f('4', '2');
38
39*/
40
41#include<utility>
42#include<type_traits>
43#include<memory>
44#include<functional>
45//#include<util/func_traits.h>
46
47namespace detail
48{
49 struct dummy {};
50
51 template<typename...>
52 struct erasure_base
53 {
54 void operator()(dummy) {};
55 };
56
57 template<typename Ret, typename... Args, typename... Fns>
58 struct erasure_base<Ret (Args...), Fns...> : erasure_base<Fns...>
59 {
60 virtual Ret operator()(Args&&...) = 0;
61 using erasure_base<Fns...>::operator();
62 };
63
64 template<typename...>
65 struct erasure;
66
67 // Base is the common erasure_base, only the base case of erasure contains the callable object
68 template<typename Base, typename Callable, typename Ret, typename... Args>
69 struct erasure<Base, Callable, Ret (Args...)> : Base
70 {
71 template<typename C>
72 erasure(C&& callable) : callable{std::forward<C>(callable)} {}
73 Ret operator()(Args&&... args) override
74 {
75 return Ret(callable(std::forward<Args>(args)...));
76 }
77 std::decay_t<Callable> callable;
78 };
79
80 // Next is the erasure type that contains the next signature
81 template<typename Base, typename Callable, typename Ret, typename... Args, typename... Fns>
82 struct erasure<Base, Callable, Ret (Args...), Fns...> : erasure<Base, Callable, Fns...>
83 {
84 using Next = erasure<Base, Callable, Fns...>;
85
86 template<typename C>
87 erasure(C&& callable) : Next{std::forward<C>(callable)} {}
88 Ret operator()(Args&&... args) override
89 {
90 return Ret(Next::callable(std::forward<Args>(args)...));
91 }
92 };
93}
94
95template<typename... Fns>
96class function
97{
98 using erasure_base = detail::erasure_base<Fns...>;
99 template<typename Callable>
100 using erasure = detail::erasure<erasure_base, Callable, Fns...>;
101 using nullptr_t = decltype(nullptr);
102
103public:
104 function() = default;
105 function(nullptr_t) {}
106 function(const function&) = delete;
107 function(function&&) = default;
108
109 template<typename Callable>
110 function(Callable&& callable) : ptr{new erasure<Callable>(std::forward<Callable>(callable))} {}
111
112 function& operator=(const function&) = delete;
113 function& operator=(function&&) = default;
114
115 ~function() = default;
116
117 template<typename... Args>
118 decltype(auto) operator()(Args&&... args)
119 {
120 if(!ptr)
121 throw std::bad_function_call{};
122 return ptr->operator()(std::forward<Args>(args)...);
123 }
124
125 void swap(function& other) {swap(ptr, other.ptr);}
126 friend void swap(function& x, function& y) noexcept {x.swap(y);}
127 operator bool() const noexcept {return ptr;}
128
129 friend bool operator==(nullptr_t, const function& f) noexcept {return !f;}
130 friend bool operator==(const function& f, nullptr_t) noexcept {return !f;}
131 friend bool operator!=(nullptr_t, const function& f) noexcept {return f;}
132 friend bool operator!=(const function& f, nullptr_t) noexcept {return f;}
133
134private:
135 std::unique_ptr<erasure_base> ptr;
136};
137
138
139// deduction guide, not core
140
141//template<typename Callable>
142//function(Callable&&) -> function<typename func_traits<Callable>::signature>;
143
144
145
146
147
148
149#endif // FUNCTION_HPP_INCLUDED