7
7
#include < sstream>
8
8
#include < string>
9
9
#include < string_view>
10
+ #include < tuple>
11
+ #include < type_traits>
10
12
11
- #include " json.hpp"
12
13
#include " config.hpp"
13
14
#include " function_storage.hpp"
15
+ #include " json.hpp"
14
16
#include " parser.hpp"
15
17
#include " renderer.hpp"
16
18
#include " template.hpp"
17
19
#include " throw.hpp"
20
+ #include " utils.hpp"
18
21
19
22
namespace inja {
20
23
@@ -25,6 +28,30 @@ class Environment {
25
28
FunctionStorage function_storage;
26
29
TemplateStorage template_storage;
27
30
31
+ template <class Arg >
32
+ static Arg get_callback_argument (const Arguments &args, size_t index) {
33
+ if constexpr (std::is_lvalue_reference_v<Arg>) {
34
+ return args[index]->get_ref <const Arg &>();
35
+ } else {
36
+ return args[index]->get <Arg>();
37
+ }
38
+ }
39
+
40
+ template <class Ret , class Func , class ... Args, size_t ... Is>
41
+ void add_callback_closure (const std::string &name, Func func,
42
+ function_signature::ArgsList<Args...> /* args*/ ,
43
+ std::index_sequence<Is...> /* seq*/ ) {
44
+ add_callback (name, sizeof ...(Args),
45
+ [func = std::move (func)](const Arguments &args) -> json {
46
+ if constexpr (std::is_same_v<Ret, void >) {
47
+ func (get_callback_argument<Args>(args, Is)...);
48
+ return {};
49
+ } else {
50
+ return func (get_callback_argument<Args>(args, Is)...);
51
+ }
52
+ });
53
+ }
54
+
28
55
protected:
29
56
LexerConfig lexer_config;
30
57
ParserConfig parser_config;
@@ -179,10 +206,41 @@ class Environment {
179
206
}
180
207
181
208
/* !
182
- @brief Adds a variadic callback
209
+ @brief Adds a callback
183
210
*/
184
- void add_callback (const std::string& name, const CallbackFunction& callback) {
185
- add_callback (name, -1 , callback);
211
+ template <class Callback >
212
+ void add_callback (const std::string &name, Callback callback) {
213
+ constexpr auto get_sig = [] {
214
+ if constexpr (std::is_object_v<Callback>) {
215
+ return function_signature::Get<decltype (&Callback::operator ())> {};
216
+ } else {
217
+ return function_signature::Get<Callback>{};
218
+ }
219
+ };
220
+ using Sig = decltype (get_sig ());
221
+ constexpr size_t num_args = std::tuple_size_v<typename Sig::ArgsTuple>;
222
+
223
+ constexpr auto is_arguments_vector = [] {
224
+ if constexpr (num_args == 1 ) {
225
+ return std::is_same_v<
226
+ std::remove_cv_t <std::remove_reference_t <
227
+ std::tuple_element_t <0 , typename Sig::ArgsTuple>>>,
228
+ Arguments>;
229
+ } else {
230
+ return false ;
231
+ }
232
+ };
233
+
234
+ if constexpr (is_arguments_vector ()) {
235
+ // If callback has the only argument of `Arguments` - fallback to adding a
236
+ // variadic callback
237
+ add_callback (name, -1 , callback);
238
+ } else {
239
+ // If it has other arguments - use it in a closure
240
+ add_callback_closure<typename Sig::Ret>(
241
+ name, std::move (callback), typename Sig::ArgsList{},
242
+ std::make_index_sequence<num_args>{});
243
+ }
186
244
}
187
245
188
246
/* !
0 commit comments