-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfunctions.cpp
More file actions
139 lines (125 loc) · 4.47 KB
/
Copy pathfunctions.cpp
File metadata and controls
139 lines (125 loc) · 4.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <memory>
#include <print>
#include <refl/refl.hpp>
struct [[refl::all]] Example {
int i = 5;
void foo(int j) { std::print("foo called with {}\n", j); }
void bar(double d) { std::print("bar called with {}\n", d); }
Example operator+(Example that) { return Example{i + that.i}; }
static void baz(bool b) { std::print("baz called with {}\n", b); }
#define REFL_CLASS Example
#include <refl/generate.inc>
};
// Base class to build a method call for a member function of T with return type R
template <typename R, typename T>
struct Method {
virtual ~Method() = default;
virtual R call() = 0; // call the method
virtual void set_this(T& t) = 0; // set this pointer
template <typename P>
void set_param(std::string_view name, P param) // set parameter, always copies it
{
assert(name != "");
// the parameter is passed as a void* through a virtual function call
// to the derived instance.
set_param_impl(name, reinterpret_cast<void*>(¶m));
}
private:
virtual void set_param_impl(std::string_view name, void* ptr) = 0;
};
// derived class with deduced types and the concrete pointer
template <auto ptr, typename R, typename T, typename... Args>
struct MethodImpl : Method<R, T> {
R call() override
{
if constexpr (std::is_same_v<void, R>) {
std::apply(
[this](auto&&... args) {
(object->*ptr)(args...);
},
params
);
} else {
return std::apply(
[this](auto&&... args) {
return (object->*ptr)(args...);
},
params
);
}
}
void set_this(T& t) override
{
object = &t;
}
private:
void set_param_impl(std::string_view name, void* param) override
{
// access meta data for type T as M
refl::with<T>([&]<typename M>() {
// search for a function F
refl::for_each_function<M>([&]<typename F>() {
// that has the same type and value as the specified pointer
if constexpr (std::is_same_v<decltype(ptr), typename F::type>) {
if constexpr (ptr == F::ptr) {
// search each parameter of F with type Arg, index I and name n
refl::for_each_parameter<F>([&]<typename Arg, int I>(std::string_view n) {
if (n == name) { // found the specified parameter
// store the value, we are casting back to the same type
std::get<I>(params) = std::move(*reinterpret_cast<Arg*>(param));
return;
}
});
}
}
});
});
}
private:
std::tuple<Args...> params; // parameter storage
T* object; // this storage
};
// an indirection to deduce the full type of ptr
template <auto ptr, typename R, typename T, typename... Args>
static auto make_method_impl(R (T::*)(Args...))
{
return std::make_unique<MethodImpl<ptr, R, T, Args...>>();
}
template <auto ptr>
static auto make_method()
{
return make_method_impl<ptr>(ptr);
}
int main()
{
// access meta data of Example as M
refl::with<Example>([]<typename M>() {
// for each function F in Example
refl::for_each_function<M>([]<typename F>() {
Example ex;
// call the function based on if it is a static or member function
if constexpr (!F::is_instance()) {
std::apply(F::ptr, typename F::parameters::types{});
} else {
std::apply(
[&](auto&&... args) {
(ex.*F::ptr)(args...);
},
typename F::parameters::types{}
);
}
});
});
Example ex;
std::string_view parameterName = "j";
int parameter = 42;
std::unique_ptr<Method<void, Example>> method = make_method<&Example::foo>();
method->set_this(ex);
method->set_param(parameterName, parameter);
method->call();
std::unique_ptr<Method<Example, Example>> method2 = make_method<&Example::operator+>();
method2->set_this(ex);
method2->set_param("that", ex);
ex = method2->call();
std::print("Result of ex + ex is {}", ex.i);
}