· 6 years ago · Oct 10, 2019, 05:32 PM
1 Вам нужно отключить /permissive-флаг, который включен по умолчанию, но все еще глючит. Это потому, что вы используете /permissive-флаг компилятора, который не установлен, но по умолчанию для MSVC.
2Если вы получаете лавину ошибок (особенно в отношении auto), возможно, вы не включили режим C ++ 14 / C ++ 17 для своего компилятора. Добавьте один из std=c++17, std=c++1zили std=c++1yк вашим опциям компилятора. По умолчанию это всегда включено для компиляторов VC ++ в Visual Studio и в друзьях, но для g ++ и clang ++ требуется флаг (если вы не используете GCC 6.0 или выше).
3_CRT_SECURE_NO_WARNINGS /Zc:twoPhase-
4_CRT_SECURE_NO_DEPRECATE
5_CRT_NONSTDC_NO_DEPRECATE
6#define SOL_ALL_SAFETIES_ON 1
7#pragma warning (disable : 4996).
8#pragma warning (disable : 26439).
9#include<iostream>
10#include"include/lua.hpp"
11#include <sol/sol.hpp>
12#include <cassert>
13using namespace std;
14using namespace sol;
15
16//Стек(англ.stack — стопка; читается стэк) — абстрактный тип данных, представляющий собой список элементов,
17//организованных по принципу LIFO(англ.last in — first out, «последний вошёл — первым вышел»)
18int main(int argc, char* argv[]) {
19
20 cout << "=== opening a state ===" << endl;
21
22 state lua; // Lua состояние.
23 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
24 lua.script("print('bark bark bark!')");
25
26 cout <<endl;
27 return 0;
28};
29
30const char* LUA = R"(
31 print('Hello world!')
32)";
33int main(int argc, char* argv[]) {
34 state lua;// Lua состояние.
35 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
36 lua.script(LUA);// запуск Lua скрипта.
37
38 return 0;
39};
40
41
42Если это работает, вы готовы начать! Первая строка создает lua_State и будет удерживать ее в течение всей области, в которой она объявлена (например, от открытия {до закрытия }). Он автоматически закроет / очистит это состояние lua, когда оно будет уничтожено.
43Вторая строка открывает одну предоставленную lua библиотеку, «base». Есть несколько других библиотек, которые поставляются с lua, которые вы можете открыть по умолчанию, и они включены в перечисление sol :: lib . Вы можете открыть несколько базовых библиотек, указав несколько sol::lib аргументов:
44
45int main(int argc, char* argv[]) {
46
47 cout << "=== basic ===" << endl;
48
49 // создаем пустое состояние lua
50 state lua;
51
52 // по умолчанию библиотеки не открываются
53 // вы можете открывать библиотеки, используя open_libraries
54 // библиотеки находятся в классе en en sol :: lib
55 lua.open_libraries(lib::base);
56
57 // вы можете открыть все библиотеки, не передавая аргументы
58 // lua.open_libraries ();
59 // вызвать код lua напрямую
60 lua.script("print('hello world')");
61
62 // вызываем код lua и проверяем, правильно ли он загружен и работает:
63 auto handler = &script_default_on_error;
64 lua.script("print('hello again, world')", handler);
65
66 // Используем пользовательский обработчик ошибок, если он вам нужен
67 // Это вызывается, когда результат плохой
68 auto simple_handler = [](lua_State*, protected_function_result result) {
69 // Вы можете просто пропустить это, чтобы сайт вызова справился с этим
70 return result;
71 };
72 // вышеуказанная лямбда идентична sol :: simple_on_error, но это
73 // показано здесь, чтобы показать, что вы можете написать что угодно
74 {
75 auto result = lua.script("print('hello hello again, world') \n return 24", simple_handler);
76 if (result.valid()) {
77 cout << "the third script worked, and a double-hello statement should appear above this one!" << endl;
78 int value = result;
79 //c_assert(value == 24);
80 }
81 else {
82 cout << "the third script failed, check the result type for more information!" << endl;
83 }
84 }
85
86 {
87 auto result = lua.script("does.not.exist", simple_handler);
88 if (result.valid()) {
89 cout << "the fourth script worked, which it wasn't supposed to! Panic!" << endl;
90 int value = result;
91 //c_assert(value == 24);
92 }
93 else {
94 error err = result;
95 cout << "the fourth script failed, which was intentional!\t\nError: " << err.what() << endl;
96 }
97 }
98
99 cout << endl;
100
101 return 0;
102};
103
104Еще пример.
105
106int main(int argc, char* argv[]) {
107const char* LUA = R"(
108 print('hello world')
109)";
110
111 state lua;// Lua состояние.
112 lua.open_libraries(lib::base, lib::package); /* открыть доп.библиотеки.
113
114 //запуск lua скрипта. Без пользовательского обработчика ошибок.
115 //lua.script(LUA);
116
117 // вызываем код lua и проверяем, правильно ли он загружен и работает:
118 auto handler = &script_default_on_error;
119 lua.script("print('hello again, world')", handler);
120
121 /* Используем пользовательский обработчик ошибок, если он вам нужен это вызывается, когда результат плохой.
122 Вы можете просто пропустить это, чтобы скрипт вызова справился с этим. Эта лямбда идентична
123 sol :: simple_on_error, но это показано здесь, чтобы показать, что вы можете написать что угодно.*/
124 typedef protected_function_result result, pro_func_res;
125 auto simple_handler = [](lua_State*, pro_func_res result) {return result; }; {
126
127 auto result = lua.script("print('hello hello again') \n return 24", simple_handler);
128 if (result.valid()) { cout << "the script is working" << endl;// если ошибок нет.
129 int value = result;} //c_assert(value == 24);
130
131 else { cout << "script call error, check the result type for more info!" << endl; }
132 }
133 return 0;
134};
135
136Вариант 2.
137
138const char* LUA = R"(
139 print('Hello world!')
140)";
141int main(int argc, char* argv[]) {
142 state lua;// Lua состояние.
143 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
144
145 typedef protected_function_result result, pfres;// Назвать структуру короче.
146 auto simple_handler = [](lua_State*, pfres res) {return res; }; {
147
148 auto res = lua.script(LUA, simple_handler);
149 if (result.valid()) {
150 cout << "the script is good working" << endl;}// если ошибок нет.
151
152 else { cout << "script call error, check the result type for more info!" << endl; }
153 }
154 return 0;
155};
156
157
158Если вы уже используете lua и просто хотите использовать его sol в некоторых местах, вы можете использовать state_view:
159используя state_view.
160
161sol::state_view точно такой же sol::state, но он не управляет временем жизни lua_State*. Таким образом, вы получаете все вкусности, которые идут с sol::state без каких-либо последствий собственности.
162Sol не имеет компонентов инициализации, которые должны намеренно оставаться живыми в течение всей программы. Он полностью самодостаточен и использует сборщики мусора lua и различные методы реализации, не требующие состояния C ++. После того, как вы это сделаете, вам доступны все возможности sol , а затем и некоторые!
163sol::state_view также полезно, когда вы хотите создать DLL, которая загружает некоторый модуль Lua через require.
164Вы также можете вызвать require и предоставить строку файла сценария или что-то, что возвращает объект, который вы установили равным чему-то в C ++. Для этого вы можете использовать требуемые функции.
165Помните, что sol может быть настолько легким, насколько вам нужно: почти все типы Lua sol принимают lua_State* аргумент, а затем второй аргумент индекса стека, то есть вы можете использовать таблицы , функции lua , сопрограммы и другие объекты, полученные из ссылок, которые предоставляют надлежащие Конструктор для вашего использования. Вы также можете установить типы пользователей и другие нужные вам вещи, не меняя всю архитектуру за один раз. int index
166Вы даже можете настроить его для работы с внешней оболочкой / фреймворком / библиотекой Lua .
167Обратите внимание, что вы также можете создавать нестандартные указатели и ссылочные типы с настраиваемым подсчетом ссылок, что также хорошо работает с системой. Смотрите unique_usertype_traits <T>, чтобы увидеть как! Пользовательские типы также упоминаются в руководстве по настройке.
168Есть несколько вещей, которые создают sol::state для вас. Вы можете прочитать об этом в документации sol :: state и вызывать эти функции напрямую, если они вам нужны.
169
170int something_in_my_system(lua_State* L) {
171 // // начните использовать sol с уже существующей системой
172 state_view lua(L); // non-owning
173
174 lua.script("print('bark bark bark!')");
175
176 // get the table off the top of the stack
177 //table expected_table(L, -1);
178 // start using it...
179
180 return 0; // or whatever you require of working with a raw function
181};
182int main(int argc, char* argv[]) {
183
184 lua_State* L = luaL_newstate();/*Функция создает новое Lua состояние. Она вызывает lua_newstate с функцией-*/
185
186 luaL_openlibs(L);
187
188 something_in_my_system(L);
189
190 lua_close(L);// закрыть состояние
191
192 return 0;
193};
194Еще пример.
195const char* LUA = R"(
196 print("state view")
197)";
198int embeds_sol(lua_State* L) {
199 // start using sol with a pre-existing system
200 state_view lua(L); // non-owning
201
202 lua.script(LUA);
203
204 return 0; // все, что требуется для работы с необработанной функцией.
205};
206int main(int argc, char* argv[]) {
207 lua_State* L = luaL_newstate();/*Функция создает новое Lua состояние.*/
208 luaL_openlibs(L);
209
210 embeds_sol(L);// функция использующая SOL.
211
212 lua_close(L);// закрыть состояние
213
214 return 0;
215};
216
217Переменные.
218Работать с переменными легко с sol, и ведет себя почти как любая ассоциативная структура массива / map, с которой вы, возможно, имели дело ранее.
219
220
221чтение
222Учитывая этот файл lua, который загружается в sol:
223
224config = {
225 fullscreen = false,
226 resolution = { x = 1024, y = 768 }
227}
228Вы можете взаимодействовать с виртуальной машиной Lua следующим образом:
229
230#define SOL_ALL_SAFETIES_ON 1
231#include <sol/sol.hpp>
232
233#include <tuple>
234#include <assert.hpp>
235#include <utility> // for pair
236
237int main() {
238
239 sol::state lua;
240 lua.script_file("variables.lua");
241 // the type "sol::state" behaves
242 // exactly like a table!
243 bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
244 sol::table config = lua["config"];
245 c_assert(!isfullscreen);
246 return 0;
247};
248
249Еще пример.
250
251const char* LUA = R"(
252x= 20
253)";
254int main(int argc, char* argv[]) {
255 state lua;// Lua состояние.
256 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
257
258 lua.script(LUA);
259
260 int full = lua["x"];/* Получить переменную x.*/
261 cout << full << endl;
262
263 return 0;
264};
265const char* LUA = R"(
266x= 20
267)";
268int main(int argc, char* argv[]) {
269 state lua;// Lua состояние.
270 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
271
272 lua.script(LUA);
273
274 sol::optional<int> int_x = lua["x"];
275 if (int_x) {
276 cout << " var this is int " << endl;
277 int x1 = lua["x"];
278 cout << x1 << endl;
279 return 0;
280 };
281
282 sol::optional<bool> boolean_x = lua["x"];
283 if (boolean_x) {
284 cout << " var this is bool " << endl;
285 bool x2 = lua["x"];
286 cout << x2 << endl;
287 return 0;
288 };
289
290 sol::optional<double> double_x = lua["x"];
291 if (double_x) {
292 cout << " var this is double " << endl;
293 double x3 = lua["x"];
294 cout << x3 << endl;
295 };
296
297 return 0;
298};
299
300int main(int argc, char* argv[]) {
301
302 state lua;// Lua состояние.
303 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
304 lua.script_file("variables.lua");
305 // the type "sol::state" behaves
306 // exactly like a table!
307 bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
308 cout << isfullscreen << endl;
309 table config = lua["config"];
310 for each (auto var in config)
311 {
312 cout << &var << endl;
313 }
314
315 return 0;
316};
317
318Из этого примера вы можете увидеть, что есть много способов извлечь нужные вам переменные. Например, чтобы определить, существует ли вложенная переменная или нет, вы можете использовать ее autoдля захвата значения table[key]поиска, а затем использовать .valid()метод:
319
320#define SOL_ALL_SAFETIES_ON 1
321#include <sol/sol.hpp>
322
323#include <tuple>
324#include <assert.hpp>
325#include <utility> // for pair
326
327int main(int argc, char* argv[]) {
328
329 state lua;// Lua состояние.
330 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
331 lua.script_file("variables.lua");
332 // test variable
333 auto bark = lua["config"]["bark"];
334 if (bark.valid()) { cout << "Branch taken: config and bark are existing variables " << endl;
335 // Branch taken: config и bark-это существующие переменные.
336 }
337 else {cout << "config and/or bark are not variables " << endl;
338 // config и / или bark не являются переменными.
339 }
340
341 return 0;
342};
343Это удобно, когда вы хотите проверить, существует ли вложенная переменная. Вы также можете проверить, присутствует ли переменная верхнего уровня или нет, с помощью sol::optional которой также проверяется, существуют ли A) ключи, в которые вы собираетесь войти, и B) тип, который вы пытаетесь получить, определенного типа:
344
345#define SOL_ALL_SAFETIES_ON 1
346#include <sol/sol.hpp>
347
348#include <tuple>
349#include <assert.hpp>
350#include <utility> // for pair
351
352};
353int main(int argc, char* argv[]) {
354
355 state lua;// Lua состояние.
356 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
357 lua.script_file("variables.lua");
358 // can also use optional
359 sol::optional<int> not_an_integer = lua["config"]["fullscreen"];
360 if (not_an_integer) {
361 cout << " var this is int " << endl;}
362
363 sol::optional<bool> is_a_boolean = lua["config"]["fullscreen"];
364 if (is_a_boolean) {
365 cout << " var this is bool " << endl;}
366
367 sol::optional<double> is_a_double = lua["not_a_variable"];
368 if (is_a_double) {cout << " var this is double " << endl;}
369 return 0;
370};
371const char* LUA = R"(
372config = {
373 fullscreen = false,
374 resolution = { x = 1024, y = 768 }
375}
376)";
377int main(int argc, char* argv[]) {
378 state lua;// Lua состояние.
379 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
380
381
382 lua.script(LUA);
383
384 bool isfullscreen = lua["config"]["fullscreen"]; // can get nested variables
385 cout << isfullscreen << endl;
386 sol::optional<int> x = lua["config"]["resolution"]["x"];
387 if (x) {
388 int x1 = lua["config"]["resolution"]["x"];
389 cout << x1 << endl;
390 }
391 return 0;
392};
393
394
395Это может пригодиться, когда даже в оптимизированном или выпускном режимах вам все еще нужна безопасность проверки. Вы также можете использовать методы get_or , если определенное значение может присутствовать, но вы просто хотите установить значение по умолчанию в другом месте:
396
397#define SOL_ALL_SAFETIES_ON 1
398#include <sol/sol.hpp>
399
400#include <tuple>
401#include <assert.hpp>
402#include <utility> // for pair
403
404int main() {
405
406 sol::state lua;
407 lua.script_file("variables.lua");
408 // this will result in a value of '24'
409 // (it tries to get a number, and fullscreen is
410 // not a number
411 int is_defaulted = lua["config"]["fullscreen"].get_or(24);
412 c_assert(is_defaulted == 24);
413
414 // This will result in the value of the config, which is 'false'
415 bool is_not_defaulted = lua["config"]["fullscreen"];
416 c_assert(!is_not_defaulted);
417
418 return 0;
419};
420const char* LUA = R"(
421config = {
422 fullscreen = 32
423}
424)";
425int main(int argc, char* argv[]) {
426 state lua;// Lua состояние.
427 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
428
429 lua.script(LUA);
430
431 int full = lua["config"]["fullscreen"].get_or(24);/*Если переменная не int,
432 то равна по умолчанию 24.*/
433 cout << full << endl;
434
435 return 0;
436};
437
438
439
440Это все, что нужно для чтения переменных!
441
442написание
443Написание становится намного проще. Даже без написания скрипта для файла или строки вы можете читать и записывать переменные в lua по своему усмотрению:
444
445#define SOL_ALL_SAFETIES_ON 1
446#include <sol/sol.hpp>
447
448#include <iostream>
449
450int main() {
451
452 sol::state lua;
453
454 // open those basic lua libraries
455 // again, for print() and other basic utilities
456 lua.open_libraries(sol::lib::base);
457
458 // value in the global table
459 lua["bark"] = 50;
460
461 // a table being created in the global table
462 lua["some_table"] = lua.create_table_with(
463 "key0", 24,
464 "key1", 25,
465 lua["bark"], "the key is 50 and this string is its value!");
466
467 // Run a plain ol' string of lua code
468 // Note you can interact with things set through sol in C++ with lua!
469 // Using a "Raw String Literal" to have multi-line goodness:
470 // http://en.cppreference.com/w/cpp/language/string_literal
471 lua.script(R"(
472
473 print(some_table[50])
474 print(some_table["key0"])
475 print(some_table["key1"])
476
477 -- a lua comment: access a global in a lua script with the _G table
478 print(_G["bark"])
479
480 )");
481
482 return 0;
483};
484Еще пример.
485
486const char* LUA = R"(
487 print(some_table[50])--"the key is 50 and this string is its value!"
488 print(some_table["key0"])--24
489 print(some_table["key1"])--25
490
491 -- a lua comment: access a global in a lua script with the _G table
492 print(_G["bark"])-- 50
493)";
494int main(int argc, char* argv[]) {
495
496 state lua;// Lua состояние.
497 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
498 //значение в глобальной таблице
499 lua["bark"] = 50;
500
501 // таблица, создаваемая в глобальной таблице.
502 lua["some_table"] = lua.create_table_with(
503 "key0", 24,"key1", 25,
504 lua["bark"], "the key is 50 and this string is its value!");
505 /* Запуск простой строчки кода lua, Примечание Вы можете взаимодействовать с вещами,
506 установленными через sol в C++ с lua! Использование "необработанного строкового литерала"
507 для многострочной доброты:*/
508 lua.script(LUA);
509
510 return 0;
511};
512
513Этот пример в значительной степени подводит итог того, что можно сделать. Обратите внимание, что синтаксис сделает эту переменную, но если вы туннелируете слишком глубоко без предварительного создания таблицы, Lua API вызовет панику (например, вызовет панику). Вы также можете лениться с чтением / записью значений: lua["non_existing_key_1"] = 1lua["does_not_exist"]["b"] = 20
514
515#define SOL_ALL_SAFETIES_ON 1
516#include <sol/sol.hpp>
517
518#include <iostream>
519
520int main() {
521
522 sol::state lua;
523
524 auto barkkey = lua["bark"];
525 if (barkkey.valid()) {
526 // Branch not taken: doesn't exist yet
527 cout << "How did you get in here, arf?!" << endl;
528 }
529
530 barkkey = 50;
531 if (barkkey.valid()) {
532 // Branch taken: value exists!
533 cout << "Bark Bjork Wan Wan Wan" << endl;
534 }
535
536 return 0;
537};
538Еще пример.
539int main(int argc, char* argv[]) {
540
541 state lua;// Lua состояние.
542 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
543 auto barkkey = lua["bark"]; //уст значение в глобальной таблице.
544
545 if (barkkey.valid()) {// значение не существует!
546 cout << "value nil" << endl;}
547 barkkey = 50;
548 if (barkkey.valid()) { // значение существует!
549 cout << "barkkey = 50" << endl; }
550
551 return 0;
552};
553
554Наконец, можно удалить ссылку / переменную, установив для нее значение с nil использованием константы sol::lua_nil в C ++:
555
556#define SOL_ALL_SAFETIES_ON 1
557#include <sol/sol.hpp>
558
559#include <iostream>
560
561int main() {
562
563 sol::state lua;
564 lua["bark"] = 50;
565 sol::optional<int> x = lua["bark"];
566 // x will have a value
567 if (x) {
568 cout << "x has no value, as expected" << endl;
569 }
570 else {
571 return -1;
572 }
573
574 lua["bark"] = sol::lua_nil;
575 sol::optional<int> y = lua["bark"];
576 // y will not have a value
577 if (y) {
578 return -1;
579 }
580 else {
581 cout << "y has no value, as expected" << endl;
582 }
583
584 return 0;
585};
586
587Еще пример.
588int main(int argc, char* argv[]) {
589
590 state lua;// Lua состояние.
591 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
592 lua["bark"] = 50;//уст значение в глобальной таблице.
593 sol::optional<int> x = lua["bark"]; // x имеет значение, получим его.
594 if (x) {cout << "x has value "<< endl;
595 }
596 else {return -1;}
597
598 lua["bark"] = sol::lua_nil;
599 sol::optional<int> y = lua["bark"]; // y не имеет значение.
600 if (y) { return -1;
601 }
602 else { cout << "y has no value " << endl; }
603
604 return 0;
605};
606
607
608
609Легко видеть, что здесь есть много вариантов сделать то, что вы хотите. Но это просто традиционные числа и строки. Что если нам нужно больше мощности, больше возможностей, чем то, что могут предложить нам эти ограниченные типы? Давайте добавим некоторые функции в классы C ++ !
610
611Sol может регистрировать все виды функций. Многие из них показаны в быстром 'n' грязном, но здесь мы обсудим множество дополнительных способов регистрации функций в системе Lua, обернутой в sol.
612
613Установка новой функции
614Имея функцию C ++, вы можете поместить ее в sol несколькими эквивалентными способами, работая аналогично тому, как работает установка переменных :
615
616Регистрация функций C ++
617#include <sol/sol.hpp>
618
619string my_function( int a, string b ) {
620 // Create a string with the letter 'D' "a" times,
621 // append it to 'b'
622 return b + string( 'D', a );
623}
624
625int main () {
626
627 sol::state lua;
628
629 lua["my_func"] = my_function; // way 1
630 lua.set("my_func", my_function); // way 2
631 lua.set_function("my_func", my_function); // way 3
632
633 // This function is now accessible as 'my_func' in
634 // lua scripts / code run on this state:
635 lua.script("some_str = my_func(1, 'Da')");
636
637 // Read out the global variable we stored in 'some_str' in the
638 // quick lua code we just executed
639 string some_str = lua["some_str"];
640 // some_str == "DaD"
641};
642
643Еще пример.
644
645string my_function(int a, string b) {
646 return b + string('D', a);
647}
648
649int main(int argc, char* argv[]) {
650
651 state lua;// Lua состояние.
652 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
653 lua["my_func"] = my_function; // way 1
654 lua.set("my_func", my_function); // way 2
655 lua.set_function("my_func", my_function); // way 3
656 // Эта функция теперь доступна как' my_func ' в
657 // lua скрипты / код выполняется в этом состоянии:
658 lua.script("some_str = my_func(1, 'Da')");
659 // Прочитайте глобальную переменную, которую мы сохранили в' some_str
660 // быстрый lua код, который мы только что выполнили
661 string some_str = lua["some_str"];
662 cout << some_str << endl;
663 return 0;
664};
665
6662
667const char* LUA = R"(
668foo(1, 3)
669)";
670void foo(int a, int b) {
671 cout << a+b << endl;
672}
673
674int main(int argc, char* argv[]) {
675
676 state lua;// Lua состояние.
677 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
678 lua.set("foo", foo); // вариант 2.
679 lua.script(LUA);// lua код, который мы только что выполнили.
680
681 return 0;
682};
683
684Один и тот же код работает со всеми видами функций, начиная с указателей на функции / переменные-члены, которые есть у вас в классе, а также с лямбдами:
685
686Регистрация функций-членов C ++
687
688struct my_class {
689 int a = 0;
690
691 my_class(int x) : a(x) {
692
693 }
694
695 int func() {
696 ++a; // increment a by 1
697 return a;
698 }
699};
700
701int main () {
702
703 sol::state lua;
704
705 // Here, we are binding the member function and a class instance: it will call the function on
706 // the given class instance
707 lua.set_function("my_class_func", &my_class::func, my_class());
708
709 // We do not pass a class instance here:
710 // the function will need you to pass an instance of "my_class" to it
711 // in lua to work, as shown below
712 lua.set_function("my_class_func_2", &my_class::func);
713
714 // With a pre-bound instance:
715 lua.script(R"(
716 first_value = my_class_func()
717 second_value = my_class_func()
718 )");
719 // first_value == 1
720 // second_value == 2
721
722 // With no bound instance:
723 lua.set("obj", my_class(24));
724 // Calls "func" on the class instance
725 // referenced by "obj" in Lua
726 lua.script(R"(
727 third_value = my_class_func_2(obj)
728 fourth_value = my_class_func_2(obj)
729 )");
730 // first_value == 25
731 // second_value == 26
732};
733Пример.
734
735
736int main(int argc, char* argv[]) {
737
738 struct my_class {
739 int b = 24;
740
741 int f() const {
742 return 24;
743 }
744
745 void g() {
746 ++b;
747 }
748 };
749
750 state lua;
751 lua.open_libraries();
752
753 table bark = lua["bark"] = lua.get_or("bark", lua.create_table());
754 bark.new_usertype<my_class>("my_class",
755 "f", &my_class::f,
756 "g", &my_class::g); // the usual
757
758 // can add functions, as well (just like the global table)
759 bark.set_function("print_my_class", [](my_class& self) {
760 cout << "my_class { b: " << self.b << " }\n"; });
761
762 // this works
763 lua.script("obj = bark.my_class.new()");
764 lua.script("obj:g()");
765
766 // calling this function also works
767 lua.script("bark.print_my_class(obj)");
768 my_class& obj = lua["obj"];
769
770 cout <<"\n";
771
772 return 0;
773};
774
775
776Вариант 2.
777
778const char* LUA = R"(
779obj = t.class.new()
780n= obj:f()
781print(n)--24
782obj:g()
783n= obj:f()
784print(n)--25
785t.print_class(obj)
786)";
787
788int main(int argc, char* argv[]) {
789 struct my_class { int b = 24;
790
791 int f() const { return b; }
792
793 void g() { ++b;}
794 };
795 state lua;
796 lua.open_libraries();
797 table bark = lua["t"] = lua.get_or("t", lua.create_table());
798 bark.new_usertype<my_class>("class", "f", &my_class::f, "g", &my_class::g);
799 //может добавить функции, классы в таблицу, использовать как глобальную таблицую)
800 bark.set_function("print_class", [](my_class& self) {
801 cout << "class { b: " << self.b << " }\n"; });// функцию выводит атрибут.
802 lua.script(LUA);
803
804 cout <<"\n";
805
806 return 0;
807};
808
809Вариант 3.
810
811
812const char* LUA = R"(
813obj = t.a.new()
814obj:show()
815t.print_class(obj)
816)";
817
818int main(int argc, char* argv[]) {
819 struct a { int x = 10;
820 a() { cout << "create object " << this << endl; }//конструктор по умолчанию
821 void show() { cout << "\nobject - " << this << "\tx = " << x << "\n\n"; }//вывести значение x на экран.
822 ~a() { cout << "destory object " << this << endl << endl; }//вызов деструктора.
823 };
824
825 state lua;
826 lua.open_libraries();
827 table bark = lua["t"] = lua.get_or("t", lua.create_table());// Глоб таблица.
828 bark.new_usertype<a>("a", "show", &a::show); /*может добавить функции, классы в таблицу,
829 использовать как глобальную таблицую*/
830 bark.set_function("print_class", [](a& self) {cout << "class { b: " << self.x << " }\n"; });// функцию выводит атрибут.
831 lua.script(LUA);
832
833 cout <<"\n";
834
835 return 0;
836};
837
838
839Функции класса-члена и переменные класса-члена будут превращены в функции при установке таким образом. Вы можете получить интуитивно понятную переменную с доступом после этого раздела, когда узнаете о пользовательских типах для C ++ в Lua , но сейчас мы просто имеем дело с функциями!obj.a = value
840
841Другой вопрос, который возникает у многих людей, касается шаблонов функций. Шаблоны функций - функции-члены или свободные функции - не могут быть зарегистрированы, потому что они не существуют, пока вы не создадите их в C ++. Поэтому, учитывая шаблонную функцию, такую как:
842
843Шаблонная функция C ++
844
845template <typename A, typename B>
846auto my_add( A a, B b ) {
847 return a + b;
848}
849Вы должны указать все аргументы шаблона, чтобы связать и использовать его, вот так:
850
851Регистрация инстанциации шаблона функции
852int main () {
853
854 sol::state lua;
855
856 // adds 2 integers
857 lua["my_int_add"] = my_add<int, int>;
858
859 // concatenates 2 strings
860 lua["my_string_combine"] = my_add<string, string>;
861
862 lua.script("my_num = my_int_add(1, 2)");
863 int my_num = lua["my_num"];
864 // my_num == 3
865
866 lua.script("my_str = my_string_combine('bark bark', ' woof woof')");
867 string my_str = lua["my_str"];
868 // my_str == "bark bark woof woof"
869};
870
8712.
872const char* LUA = R"(
873my_num = my_combine(1, 2)
874)";
875template <class t1, class t2>
876auto my_add(t1 a, t1 b) { return a + b; };
877
878int main(int argc, char* argv[]) {
879
880 state lua;// Lua состояние.
881 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
882
883 lua["my_combine"] = sol::overload(my_add<int, int>, my_add<string, string>);
884
885 lua.script(LUA);
886 int num = lua["my_num"];
887 cout << num << endl;
888
889 lua.script("my_str = my_combine('my', ' work')");
890 string str = lua["my_str"];
891 cout << str << endl;
892
893 return 0;
894};
895
896
897Обратите внимание, что мы связываем две отдельные функции. Что если мы хотим связать только одну функцию, но она будет вести себя по-разному в зависимости от того, с какими аргументами она вызывается? Это называется перегрузкой, и это можно сделать с помощью sol :: overload следующим образом:
898
899Регистрация экземпляров шаблона функции C ++
900int main () {
901
902 sol::state lua;
903
904 // adds 2 integers
905 lua["my_combine"] = sol::overload( my_add<int, int>, my_add<string, string> );
906
907 lua.script("my_num = my_combine(1, 2)");
908 lua.script("my_str = my_combine('bark bark', ' woof woof')");
909 int my_num = lua["my_num"];
910 string my_str = lua["my_str"];
911 // my_num == 3
912 // my_str == "bark bark woof woof"
913};
914
915В качестве перегрузке шаблонных методов.
916
917int main(int argc, char* argv[]) {
918 state lua;// Lua состояние.
919 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
920
921 lua["my_combine"] = sol::overload( my_add<int, int>, my_add<string, string> );
922
923 lua.script("my_num = my_combine(1, 2)");
924 int my_num = lua["my_num"];
925 cout << my_num << endl;
926
927 lua.script("my_str = my_combine('my', ' work')");
928 string my_str = lua["my_str"];
929
930 cout << my_str << endl;
931 return 0;
932};
933
934
935Это полезно для функций, которые могут принимать несколько типов и должны вести себя по-разному в зависимости от этих типов. Вы можете установить столько перегрузок, сколько хотите, и они могут быть разных типов.
936
937В качестве примечания, связывание функций с параметрами по умолчанию не связывает по волшебству несколько версий функции, вызываемой с параметрами по умолчанию. Вместо этого вы должны использовать sol :: overload .
938
939В качестве примечания, пожалуйста, убедитесь, что понимаете Убедитесь, что вы понимаете последствия привязки лямбда / вызываемой структуры различными способами и что это значит для вашего кода!
940
941
942Получение функции от Lua.
943
944Есть 2 способа получить функцию от Lua. Один с sol :: function, а другой - более продвинутая оболочка с sol :: protected_function . Используйте их для извлечения вызываемых из Lua и вызова основной функции двумя способами:
945
946Получение sol :: function
947int main () {
948
949 sol::state lua;
950
951 lua.script(R"(
952 function f (a)
953 return a + 5
954 end
955 )");
956
957 // Get and immediately call
958 int x = lua["f"](30);
959 // x == 35
960
961 // Store it into a variable first, then call
962 sol::function f = lua["f"];
963 int y = f(20);
964 // y == 25
965};
966
967Вариант 2.
968
969const char* LUA = R"(
970 function foo (a)
971 return a + 5
972 end
973)";
974int main(int argc, char* argv[]) {
975 state lua;// Lua состояние.
976 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
977 lua.script(LUA);// Вызвать функцию и получить результат.
978 int x = lua["foo"](30);
979 cout << x << endl;// x == 35
980
981 lua.script(LUA);// Сначала сохранить результат в переменной, затем вызвать.
982 sol::function f = lua["foo"];
983 int y = f(20);
984 cout << y << endl; // y == 25
985
986 return 0;
987};
988
989Вариант 3.
990
991
992const char* LUA = R"(
993 function foo ()
994print(223)
995 end
996 function f()
997print("func f")
998 end
999)";
1000int main(int argc, char* argv[]) {
1001 state lua;// Lua состояние.
1002 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1003 lua.script(LUA);// Вызвать функцию и получить результат.
1004 lua["foo"]();
1005
1006 lua.script(LUA);// Сначала сохранить результат в переменной, затем вызвать.
1007 sol::function f = lua["f"];
1008 f();
1009
1010 return 0;
1011};
1012
1013
1014
1015В Lua вы можете получить все, что можно вызвать, включая функции C ++, которые вы используете, set_function или аналогичные. sol::protected_function ведет себя аналогично sol::function, но имеет переменную error_handler, которую вы можете установить в функцию Lua. Это ловит все ошибки и запускает их через функцию обработки ошибок:
1016
1017Получение sol :: protected_function
1018int main () {
1019 sol::state lua;
1020
1021 lua.script(R"(
1022 function handler (message)
1023 return "Handled this message: " .. message
1024 end
1025
1026 function f (a)
1027 if a < 0 then
1028 error("negative number detected")
1029 end
1030 return a + 5
1031 end
1032 )");
1033
1034 sol::protected_function f = lua["f"];
1035 f.error_handler = lua["handler"];
1036
1037 sol::protected_function_result result = f(-500);
1038 if (result.valid()) {
1039 // Call succeeded
1040 int x = result;
1041 }
1042 else {
1043 // Call failed
1044 sol::error err = result;
1045 string what = err.what();
1046 // 'what' Should read
1047 // "Handled this message: negative number detected"
1048 }
1049};
1050
1051Вариант 2.
1052
1053
1054const char* LUA = R"(
1055 function handler (message)
1056 return "Handled this message: " .. message
1057 end
1058
1059 function f (a)
1060 if a < 0 then
1061 error("negative number detected")
1062 end
1063 return a + 5
1064 end
1065
1066)";
1067int main(int argc, char* argv[]) {
1068 state lua;// Lua состояние.
1069 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1070 lua.script(LUA);
1071 typedef sol::protected_function profunc;
1072 typedef sol::protected_function_result profunc_res;
1073 profunc f = lua["f"];
1074 f.error_handler = lua["handler"];
1075
1076 lua.script(LUA);
1077 profunc_res result = f(-500);
1078 if (result.valid()) { // вызов успешен.
1079 int x = result;
1080 cout << x << endl;
1081 }
1082 else {// Вызов функции с ошибкой.
1083 sol::error err = result;// 'what' Should read
1084 string what = err.what(); // "Handled this message: negative number detected"
1085
1086 cout << what << endl;// вывести ошибку.
1087 }
1088
1089 return 0;
1090};
1091
1092Несколько возвратов в и из Lua Вы можете вернуть несколько параметров в Lua и из него, используя tuple/ pair классы, предоставляемые C ++. Это позволяет вам также использовать sol::tie для установки возвращаемых значений в предварительно объявленные элементы. Чтобы получить несколько возвратов, просто запросите tuple тип из результата вычисления функции или sol::tie связку предварительно объявленных переменных вместе и установите результат, равный этому:
1093
1094Несколько возвратов от Lua
1095int main () {
1096 sol::state lua;
1097
1098 lua.script("function f (a, b, c) return a, b, c end");
1099
1100 tuple<int, int, int> result;
1101 result = lua["f"](1, 2, 3);
1102 // result == { 1, 2, 3 }
1103 int a, int b;
1104 string c;
1105 sol::tie( a, b, c ) = lua["f"](1, 2, "bark");
1106 // a == 1
1107 // b == 2
1108 // c == "bark"
1109}
1110Вы также можете вернуть несколько элементов самостоятельно из связанной с C ++ функции. Здесь мы собираемся связать лямбду C ++ с Lua, а затем вызвать ее через Lua и получить tuple выход с другой стороны:
1111Вариант 2.
1112
1113const char* LUA = R"(
1114function f (a, b, c) return a, b, c end
1115)";
1116int main(int argc, char* argv[]) {
1117 state lua;// Lua состояние.
1118 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1119
1120 lua.script(LUA);
1121
1122 tuple<int, int, int> result;
1123 result = lua["f"](10, 20, 30); // result == { 10, 20, 30 }
1124 cout << get<0>(result) << endl;// 10
1125 return 0;
1126};
1127
1128Вариант 3.
1129
1130template<size_t I = 0, typename... Tp>
1131inline typename enable_if<I == sizeof...(Tp), void>::type
1132print(tuple<Tp...>& t)
1133{ }
1134
1135template<size_t I = 0, typename... Tp>
1136inline typename enable_if < I < sizeof...(Tp), void>::type
1137 print(tuple<Tp...>& t)
1138{
1139 cout <<get<I>(t)<< " ";
1140 print<I + 1, Tp...>(t);
1141}
1142const char* LUA = R"(
1143function f (a, b, c) return a+1, b+2, c+3 end
1144)";
1145int main(int argc, char* argv[]) {
1146 state lua;// Lua состояние.
1147 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1148
1149 lua.script(LUA);
1150
1151 tuple<int, int, int> res;
1152 res = lua["f"](10, 20, 30); // result == { 10, 20, 30 }
1153 print(res);
1154
1155 return 0;
1156};
1157
1158
1159
1160Многократное возвращение в Lua
1161
1162int main () {
1163 sol::state lua;
1164
1165 lua["f"] = [](int a, int b, sol::object c) {
1166 // sol::object can be anything here: just pass it through
1167 return make_tuple( a, b, c );
1168 };
1169
1170 tuple<int, int, int> result = lua["f"](1, 2, 3);
1171 // result == { 1, 2, 3 }
1172
1173 tuple<int, int, string> result2;
1174 result2 = lua["f"](1, 2, "Arf?")
1175 // result2 == { 1, 2, "Arf?" }
1176
1177 int a, int b;
1178 string c;
1179 sol::tie( a, b, c ) = lua["f"](1, 2, "meow");
1180 // a == 1
1181 // b == 2
1182 // c == "meow"
1183}
1184
1185Обратите внимание, что мы используем sol :: object для переноса через «любое значение» из Lua. Вы также можете использовать sol::make_object для создания объекта из некоторого значения, чтобы он также мог быть возвращен в Lua.
1186
1187Любое возвращение в и из Lua
1188На это намекали в предыдущем примере кода, но sol::object это хороший способ передать «любой тип» обратно в Lua (пока мы все ждем, variant<...>чтобы его реализовали и отправили разработчики компилятора / библиотеки C ++).
1189
1190Он может быть использован как так, в сочетании с sol::this_state:
1191
1192Верни что-нибудь в Луа
1193sol::object fancy_func (sol::object a, sol::object b, sol::this_state s) {
1194 sol::state_view lua(s);
1195 if (a.is<int>() && b.is<int>()) {
1196 return sol::make_object(lua, a.as<int>() + b.as<int>());
1197 }
1198 else if (a.is<bool>()) {
1199 bool do_triple = a.as<bool>();
1200 return sol::make_object(lua, b.as<double>() * ( do_triple ? 3 : 1 ) );
1201 }
1202 return sol::make_object(lua, sol::lua_nil);
1203}
1204
1205int main () {
1206 sol::state lua;
1207
1208 lua["f"] = fancy_func;
1209
1210 int result = lua["f"](1, 2);
1211 // result == 3
1212 double result2 = lua["f"](false, 2.5);
1213 // result2 == 2.5
1214
1215 // call in Lua, get result
1216 lua.script("result3 = f(true, 5.5)");
1217 double result3 = lua["result3"];
1218 // result3 == 16.5
1219};
1220
1221Вариант 2.
1222
1223sol::object fancy_func(sol::object a, sol::object b, sol::this_state s) {
1224 sol::state_view lua(s);
1225 if (a.is<int>() && b.is<int>()) {
1226 return sol::make_object(lua, a.as<int>() + b.as<int>());
1227 }
1228 else if (a.is<bool>()) {
1229 bool do_triple = a.as<bool>();
1230 return sol::make_object(lua, b.as<double>() * (do_triple ? 3 : 1));
1231 }
1232 return sol::make_object(lua, sol::lua_nil);
1233};
1234
1235int main(int argc, char* argv[]) {
1236 state lua;// Lua состояние.
1237 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1238
1239 lua["f"] = fancy_func;
1240
1241 int res = lua["f"](1, 2);
1242 cout << res << endl;// 3
1243
1244 double res1 = lua["f"](false, 2.5);
1245 cout << res1 << endl;// 2.5
1246
1247 lua.script("result3 = f(true, 5.5)");
1248 double res3 = lua["result3"];
1249 cout << res3 << endl;// res3 == 16.5
1250
1251 return 0;
1252};
1253
1254Вариант 3.
1255
1256
1257const char* LUA = R"(
1258result3 = f(65)
1259)";
1260
1261object fancy_func(object a, this_state lua) {
1262
1263 if (a.is<int>()) {
1264 return make_object(lua, a.as<int>());
1265 }
1266 else if (a.is<bool>()) {
1267 bool do_bool = a.as<bool>();
1268 return make_object(lua, (do_bool ? "true" : "false"));
1269 }
1270
1271 return make_object(lua, sol::lua_nil);
1272};
1273
1274int main(int argc, char* argv[]) {
1275 state lua;// Lua состояние.
1276 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1277
1278 lua["f"] = fancy_func;
1279
1280 lua.script(LUA);
1281 double res3 = lua["result3"];
1282 cout << res3 << endl;// res3 == 16.5
1283
1284 return 0;
1285};
1286
1287
1288
1289
1290Это охватывает почти все, что вам нужно знать о функциях и о том, как они взаимодействуют с sol. Для некоторых продвинутых уловок и изящных вещей, проверьте sol :: this_state и sol :: variadic_args . Следующая остановка в этом уроке о типах C ++ (usertypes) в Lua ! Если вам нужно немного больше информации о функциях на стороне C ++ и о том, как наилучшим образом использовать аргументы из C ++ .
1291
1292
1293C ++ в Lua
1294Использование пользовательских типов («usertype» или просто «udt») просто с sol. Если вы не вызываете какие-либо переменные или функции-члены, вам даже не нужно «регистрировать» тип пользователя: просто пропустите его. Но если вам нужны переменные и функции для вашего пользовательского типа внутри Lua, вам нужно зарегистрировать его. Мы собираемся привести короткий пример, который включает в себя кучу информации о том, как работать с вещами.
1295
1296Возьмите эту player структуру в C ++ в заголовочном файле:
1297
1298player.hpp
1299
1300#include <iostream>
1301
1302struct player {
1303public:
1304 int bullets;
1305 int speed;
1306
1307 player()
1308 : player(3, 100) {
1309
1310 }
1311
1312 player(int ammo)
1313 : player(ammo, 100) {
1314
1315 }
1316
1317 player(int ammo, int hitpoints)
1318 : bullets(ammo), hp(hitpoints) {
1319
1320 }
1321
1322 void boost() {
1323 speed += 10;
1324 }
1325
1326 bool shoot() {
1327 if (bullets < 1)
1328 return false;
1329 --bullets;
1330 return true;
1331 }
1332
1333 void set_hp(int value) {
1334 hp = value;
1335 }
1336
1337 int get_hp() const {
1338 return hp;
1339 }
1340
1341private:
1342 int hp;
1343};
1344Это довольно минимальный класс, но мы не хотим переписывать это с помощью metatables в Lua. Мы хотим, чтобы это было частью Lua легко. Ниже приведен код Lua, который мы хотели бы иметь для правильной работы:
1345
1346player_script.lua
1347
1348p1 = player.new(2)
1349
1350-- p2 is still here from being
1351-- set with lua["p2"] = player(0); below
1352local p2shoots = p2:shoot()
1353assert(not p2shoots)
1354-- had 0 ammo
1355
1356-- set variable property setter
1357p1.hp = 545
1358-- get variable through property unqualified_getter
1359print(p1.hp)
1360assert(p1.hp == 545)
1361
1362local did_shoot_1 = p1:shoot()
1363print(did_shoot_1)
1364print(p1.bullets)
1365local did_shoot_2 = p1:shoot()
1366print(did_shoot_2)
1367print(p1.bullets)
1368local did_shoot_3 = p1:shoot()
1369print(did_shoot_3)
1370
1371-- can read
1372print(p1.bullets)
1373-- would error: is a readonly variable, cannot write
1374-- p1.bullets = 20
1375
1376p1:boost()
1377-- call the function we define at runtime from a Lua script
1378p1:brake()
1379
1380
1381вариант 1.
1382
1383struct player {
1384 player() {this->hp = 10;}
1385
1386 void boost() { cout << hp << endl; }
1387
1388private:
1389 int hp;
1390};
1391
1392const char* LUA = R"(
1393p1 = player.new()
1394
1395p1:boost()
1396
1397)";
1398
1399int main(int argc, char* argv[]) {
1400 state lua;// Lua состояние.
1401 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1402
1403 // сделать usertype метастабильным
1404 sol::usertype<player> player_type = lua.new_usertype<player>("player",
1405 sol::constructors<player()>()); // 1 конструктор.
1406 player_type["boost"] = &player::boost;// типичная функция-член.
1407
1408 lua.script(LUA);
1409
1410 return 0;
1411};
1412
1413Вариант 2.
1414struct a {
1415 int x = 10;
1416 a() { cout << "create object " << this << endl; }//конструктор по умолчанию
1417
1418 void show() { cout << "\nobject - " << this << "\tx = " << x << "\n\n"; }//вывести значение x на экран.
1419
1420 ~a() { cout << "destory object " << this << endl << endl; }//вызов деструктора.
1421};
1422
1423
1424const char* LUA = R"(
1425p1 = a.new()
1426
1427p1:show()
1428p2 = a.new()
1429
1430p2:show()
1431
1432)";
1433
1434int main(int argc, char* argv[]) {
1435 state lua;// Lua состояние.
1436 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1437
1438 // сделать usertype метастабильным
1439 usertype<a> player_type = lua.new_usertype<a>("a",constructors<a()>()); // 1 конструктор.
1440 player_type["show"] = &a::show;// типичная функция-член.
1441
1442 lua.script(LUA);
1443
1444 return 0;
1445};
1446
1447
1448
1449Для этого вы связываете вещи, используя new_usertype метод и, как показано ниже. Эти методы используются как для таблицы, так и для состояния (_view) , но мы собираемся просто использовать его для state:
1450
1451main.cpp
1452
1453#define SOL_ALL_SAFETIES_ON 1
1454#include <sol/sol.hpp>
1455
1456#include "player.hpp"
1457
1458#include <iostream>
1459
1460int main() {
1461 sol::state lua;
1462
1463 lua.open_libraries(sol::lib::base);
1464
1465 // note that you can set a
1466 // userdata before you register a usertype,
1467 // and it will still carry
1468 // the right metatable if you register it later
1469
1470 // set a variable "p2" of type "player" with 0 ammo
1471 lua["p2"] = player(0);
1472
1473 // make usertype metatable
1474 sol::usertype<player> player_type = lua.new_usertype<player>("player",
1475 // 3 constructors
1476 sol::constructors<player(), player(int), player(int, int)>());
1477
1478 // typical member function that returns a variable
1479 player_type["shoot"] = &player::shoot;
1480 // typical member function
1481 player_type["boost"] = &player::boost;
1482
1483 // gets or set the value using member variable syntax
1484 player_type["hp"] = sol::property(&player::get_hp, &player::set_hp);
1485
1486 // read and write variable
1487 player_type["speed"] = &player::speed;
1488 // can only read from, not write to
1489 // .set(foo, bar) is the same as [foo] = bar;
1490 player_type.set("bullets", sol::readonly(&player::bullets));
1491
1492 lua.script_file("prelude_script.lua");
1493 lua.script_file("player_script.lua");
1494 return 0;
1495}
1496
1497В сценарии используется еще один метод, которого нет в C ++ или который не определен в коде C ++ для привязки пользовательского типа, называется brake. Даже если метод не существует в C ++, вы можете добавить методы в таблицу классов в Lua:
1498
1499prelude_script.lua
1500function player:brake ()
1501 self.speed = 0
1502 print("we hit the brakes!")
1503end
1504Теперь этот сценарий должен работать нормально, и вы можете наблюдать и играть со значениями. Еще больше вещей, которые вы можете сделать , описано в другом месте, например, функции инициализатора (поддержка частных конструкторов / деструкторов), «статические» функции, которые можно вызывать , и перегруженные функции-члены. Вы можете даже связать глобальные переменные (даже по ссылке с ) с помощью. Есть много чего попробовать!
1505
1506name.my_function( ... ) refsol::var
1507
1508Это мощный способ разрешить повторное использование кода C ++ из Lua, помимо простой регистрации функций, и должен помочь вам получить более сложные классы и структуры данных! Однако в случае, когда вам нужно больше настроек, чем просто пользовательских типов, вы можете настроить sol так, чтобы он в большей степени соответствовал вашим желаниям, используя нужные структуры настройки и расширения.
1509
1510Вы можете проверить этот код и более сложный код в каталоге примеров, посмотрев usertype_примеры с префиксом.
1511
1512собственность
1513Владение важно при управлении ресурсами в C ++. У sol есть много семантик владения, которые по умолчанию безопасны. Ниже приведены правила.
1514
1515владение объектом
1516Вы можете взять ссылку на что-то, что существует в Lua, вытащив sol :: reference или sol :: object :
1517
1518object_lifetime.cpp
1519
1520#define SOL_ALL_SAFETIES_ON 1
1521#include <sol/sol.hpp>
1522
1523#include <string>
1524#include <iostream>
1525
1526int main () {
1527 sol::state lua;
1528 lua.open_libraries(sol::lib::base);
1529
1530 lua.script(R"(
1531 obj = "please don't let me die";
1532 )");
1533
1534 sol::object keep_alive = lua["obj"];
1535 lua.script(R"(
1536 obj = nil;
1537 function say(msg)
1538 print(msg)
1539 end
1540 )");
1541
1542 lua.collect_garbage();
1543
1544 lua["say"](lua["obj"]);
1545 // still accessible here and still alive in Lua
1546 // even though the name was cleared
1547 string message = keep_alive.as<string>();
1548 cout << message << endl;
1549
1550 // Can be pushed back into Lua as an argument
1551 // or set to a new name,
1552 // whatever you like!
1553 lua["say"](keep_alive);
1554
1555 return 0;
1556};
1557
1558Вариант 2.
1559int main(int argc, char* argv[]) {
1560 state lua;// Lua состояние.
1561 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1562
1563 lua.script(R"(
1564 obj = "i object";
1565 )");
1566
1567 object keep_alive = lua["obj"];/*Вы можете взять ссылку на что - то,
1568 что существует в Lua, вытащив reference или object*/
1569 lua.script(R"(
1570 obj = nil;
1571 function say(msg)
1572 print(msg)
1573 end
1574 )");
1575
1576 lua.collect_garbage();
1577 lua["say"](lua["obj"]);// вызвать функцию say. nil.
1578
1579 // все еще доступен здесь и все еще жив в Lua
1580 // даже если имя было очищено
1581 string msg = keep_alive.as<string>();// Сохраним значение значение obj в строке.
1582 cout << msg << endl;
1583
1584
1585 // Может быть возвращен в Lua в качестве аргумента
1586 // или установить новое имя,
1587 // что вам нравится!
1588 lua["say"](keep_alive);
1589
1590
1591 return 0;
1592};
1593
1594
1595
1596Все объекты должны быть уничтожены до того, как sol :: state будет уничтожен, в противном случае вы получите висячие ссылки на состояние Lua, и вещи будут взрываться ужасным, ужасным образом.
1597
1598Это относится не только к sol :: object : все типы, производные от sol :: reference и sol :: object ( sol :: table sol :: userdata и т. Д.), Должны быть очищены до того, как состояние выйдет из области видимости.
1599
1600
1601
1602
1603
1604
1605владение указателем.
1606Sol не будет владеть необработанными указателями: необработанные указатели не владеют ничем. sol не будет удалять необработанные указатели, потому что они не имеют (и не должны) ничего:
1607
1608pointer_lifetime.cpp
1609#define SOL_ALL_SAFETIES_ON 1
1610#include <sol/sol.hpp>
1611
1612struct my_type {
1613 void stuff() {
1614 }
1615};
1616
1617int main () {
1618
1619 sol::state lua;
1620 // AAAHHH BAD
1621 // dangling pointer!
1622 lua["my_func"] = []() -> my_type* { return new my_type(); };
1623
1624 // AAAHHH!
1625 lua.set("something", new my_type());
1626
1627 // AAAAAAHHH!!!
1628 lua["something_else"] = new my_type();
1629 return 0;
1630}
1631
1632Используйте / верните unique_ptr или shared_ptr вместо или просто верните значение:
1633
1634(умные указатели) pointer_lifetime.cpp
1635
1636#define SOL_ALL_SAFETIES_ON 1
1637#include <sol/sol.hpp>
1638
1639struct my_type {
1640 void stuff() {
1641 }
1642};
1643
1644int main () {
1645
1646 sol::state lua;
1647 // AAAHHH BAD
1648 // dangling pointer!
1649 lua["my_func"] = []() -> my_type* { return new my_type(); };
1650
1651 // AAAHHH!
1652 lua.set("something", new my_type());
1653
1654 // AAAAAAHHH!!!
1655 lua["something_else"] = new my_type();
1656 return 0;
1657}
1658
1659Если у вас есть что-то, что, как вы знаете, будет длиться долго, и вы просто хотите передать это Lua в качестве справки, то это тоже хорошо
1660
1661(статический) pointer_lifetime.cpp
1662#define SOL_ALL_SAFETIES_ON 1
1663#include <sol/sol.hpp>
1664
1665struct my_type {
1666 void stuff() {
1667 }
1668};
1669
1670int main () {
1671
1672 sol::state lua;
1673 lua["my_func5"] = []() -> my_type* {
1674 static my_type mt;
1675 return &mt;
1676 };
1677 return 0;
1678}
1679
1680Sol может обнаружить nullptr, поэтому, если вы вернете его, не будет никакого зависания, потому что sol::lua_nil будет нажат. Но если вы знаете, что это nil заранее, пожалуйста, верните nullptr_tили sol::lua_nil:
1681
1682(nil / nullptr) pointer_lifetime.cpp
1683#define SOL_ALL_SAFETIES_ON 1
1684#include <sol/sol.hpp>
1685
1686struct my_type {
1687 void stuff() {
1688 }
1689};
1690
1691int main () {
1692
1693 sol::state lua;
1694 // THIS IS STILL BAD DON'T DO IT AAAHHH BAD
1695 // return a unique_ptr that's empty instead
1696 // or be explicit!
1697 lua["my_func6"] = []() -> my_type* { return nullptr; };
1698
1699 // :ok:
1700 lua["my_func7"] = []() -> nullptr_t { return nullptr; };
1701
1702 // :ok:
1703 lua["my_func8"] = []() -> unique_ptr<my_type> {
1704 // default-constructs as a nullptr,
1705 // gets pushed as nil to Lua
1706 return unique_ptr<my_type>();
1707 // same happens for shared_ptr
1708 };
1709
1710 // Acceptable, it will set 'something' to nil
1711 // (and delete it on next GC if there's no more references)
1712 lua.set("something", nullptr);
1713
1714 // Also fine
1715 lua["something_else"] = nullptr;
1716
1717 return 0;
1718}
1719эфермальные (прокси) объекты
1720Прокси и типы результатов являются однодневными. Они полагаются на стек Lua, а их конструкторы / деструкторы взаимодействуют со стеком Lua. Это означает, что они совершенно небезопасны, чтобы возвращаться из функций в C ++, без особого внимания к тому, как они используются, что часто требует полагаться на поведение, определяемое реализацией.
1721
1722Пожалуйста, будьте осторожны при использовании (protected_) function_result , load_result (особенно многократная загрузка / функция приводит к одной функции C ++!) Stack_reference и подобных основанных на стеке вещах. Если вы хотите вернуть эти вещи, подумайте
1723
1724добавляя свои собственные типы
1725Иногда, перекрывая золя, чтобы сделать его обрабатывать некоторые struct«S и class» эс как нечто иное , чем просто UserData желательно. Способ сделать это состоит в том, чтобы воспользоваться преимуществами 4 пунктов настройки для Sol. Это sol_lua_check, sol_lua_get, sol_lua_push, и sol_lua_check_get.
1726
1727Это шаблон класса / структуры, поэтому вы будете переопределять их, используя технику C ++, которая вызывает специализацию класса / структуры . Ниже приведен пример структуры, которая разбивается на две части при движении в направлении C ++ -> Lua, а затем возвращается в структуру при переходе в Lua -> C ++:
1728
1729
1730#define SOL_ALL_SAFETIES_ON 1
1731#include <sol/sol.hpp>
1732
1733#include <iostream>
1734#include "assert.hpp"
1735
1736struct two_things {
1737 int a;
1738 bool b;
1739};
1740
1741template <typename Handler>
1742bool sol_lua_check(sol::types<two_things>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking) {
1743 // indices can be negative to count backwards from the top of the stack,
1744 // rather than the bottom up
1745 // to deal with this, we adjust the index to
1746 // its absolute position using the lua_absindex function
1747 int absolute_index = lua_absindex(L, index);
1748 // Check first and second second index for being the proper types
1749 bool success = sol::stack::check<int>(L, absolute_index, handler) && sol::stack::check<bool>(L, absolute_index + 1, handler);
1750 tracking.use(2);
1751 return success;
1752}
1753
1754two_things sol_lua_get(sol::types<two_things>, lua_State* L, int index, sol::stack::record& tracking) {
1755 int absolute_index = lua_absindex(L, index);
1756 // Get the first element
1757 int a = sol::stack::get<int>(L, absolute_index);
1758 // Get the second element,
1759 // in the +1 position from the first
1760 bool b = sol::stack::get<bool>(L, absolute_index + 1);
1761 // we use 2 slots, each of the previous takes 1
1762 tracking.use(2);
1763 return two_things{ a, b };
1764}
1765
1766int sol_lua_push(sol::types<two_things>, lua_State* L, const two_things& things) {
1767 int amount = sol::stack::push(L, things.a);
1768 // amount will be 1: int pushes 1 item
1769 amount += sol::stack::push(L, things.b);
1770 // amount 2 now, since bool pushes a single item
1771 // Return 2 things
1772 return amount;
1773};
1774
1775int main() {
1776 cout << "=== customization ===" << endl;
1777 cout << boolalpha;
1778
1779 sol::state lua;
1780 lua.open_libraries(sol::lib::base);
1781//Это базовая формула, которой вы можете следовать, чтобы распространить ее на свои собственные классы. Использование его в остальной части библиотеки должно быть беспроблемным:
1782 // Create a pass-through style of function
1783 lua.script("function f ( a, b ) print(a, b) return a, b end");
1784
1785 // get the function out of Lua
1786 sol::function f = lua["f"];
1787
1788 two_things things = f(two_things{ 24, false });
1789 c_assert(things.a == 24);
1790 c_assert(things.b == false);
1791 // things.a == 24
1792 // things.b == true
1793
1794 cout << "things.a: " << things.a << endl;
1795 cout << "things.b: " << things.b << endl;
1796 cout << endl;
1797
1798 return 0;
1799}
1800
1801Вариант 1.
1802
1803// индексы могут быть отрицательными для обратного отсчета от вершины стека,
1804 // а не снизу вверх
1805 // чтобы справиться с этим, мы настраиваем индекс на
1806 // / / его абсолютное положение с помощью функции индекса lua_abs
1807 // Проверьте первый и второй второй индекс на наличие правильных типов
1808 // Получить первый элемент
1809 // Получить второй элемент,
1810 // в положении +1 от первого
1811 // мы используем 2 слота, каждый из предыдущих занимает 1
1812 // сумма будет 1: int толкает 1 пункт
1813 // сумма 2 теперь, так как bool толкает один элемент
1814 // Вернуть 2 вещи / / создать сквозной стиль функции
1815 // получить функцию из Lua
1816struct two_things {
1817 int a;
1818 bool b;
1819};
1820
1821template <typename Handler>
1822bool sol_lua_check(types<two_things>, lua_State* L, int index, Handler&& handler, stack::record& tracking) {
1823 int absolute_index = lua_absindex(L, index);
1824 bool success = stack::check<int>(L, absolute_index, handler) && stack::check<bool>(L, absolute_index + 1, handler);
1825 tracking.use(2);
1826 return success;
1827}
1828
1829two_things sol_lua_get(types<two_things>, lua_State* L, int index, stack::record& tracking) {
1830 int absolute_index = lua_absindex(L, index);
1831 int a = stack::get<int>(L, absolute_index);
1832 bool b = stack::get<bool>(L, absolute_index + 1);
1833 tracking.use(2);
1834 return two_things{ a, b };
1835}
1836
1837int sol_lua_push(types<two_things>, lua_State* L, const two_things& things) {
1838 int amount = stack::push(L, things.a);
1839 amount += stack::push(L, things.b);
1840 return amount;
1841};
1842
1843
1844int main(int argc, char* argv[]) {
1845 state lua;// Lua состояние.
1846 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1847//Это базовая формула, которой вы можете следовать, чтобы распространить ее на свои собственные классы. Использование его в остальной части библиотеки должно быть беспроблемным:
1848
1849 lua.script("function f ( a, b ) print(a, b) return a, b end");
1850
1851 sol::function f = lua["f"];
1852
1853 two_things things = f(two_things{ 24, false });
1854 // things.a == 24
1855 // things.b == true
1856
1857 cout << "things.a: " << things.a << endl;
1858 cout << "things.b: " << things.b << endl;
1859 cout << endl;
1860
1861 return 0;
1862};
1863Вариант 1.
1864
1865struct t {
1866 int a;
1867};
1868
1869template <typename Handler>
1870bool sol_lua_check(types<t>, lua_State* L, int index, Handler&& handler, stack::record& tracking) {
1871 int absolute_index = lua_absindex(L, index);/* индексы могут быть отрицательными для обратного отсчета от вершины
1872 стека, а не снизу вверх чтобы справиться с этим, мы настраиваем индекс на его абсолютное
1873 положение с помощью функции индекса lua_abs*/
1874 bool success = stack::check<int>(L, absolute_index, handler);/* Проверить первый индекс на правильный тип.*/
1875 tracking.use(1);// сколько вы используете.
1876 return success;
1877};
1878
1879t sol_lua_get(types<t>, lua_State* L, int index, stack::record& tracking) {
1880 int absolute_index = lua_absindex(L, index);// Получить элемент из стека.
1881 int a = stack::get<int>(L, absolute_index);
1882 tracking.use(1);
1883 return t{ a };
1884};
1885int sol_lua_push(types<t>, lua_State* L, const t& things) {
1886 int amount = stack::push(L, things.a);// Отравить в стек int.
1887 return amount;
1888};
1889
1890int main(int argc, char* argv[]) {
1891 state lua;// Lua состояние.
1892 lua.open_libraries(lib::base, lib::package); // открыть доп.библиотеки.
1893/*Это базовая формула, которой вы можете следовать, чтобы распространить ее на свои собственные классы.
1894Использование его в остальной части библиотеки должно быть беспроблемным:*/
1895
1896 lua.script("function f (a) print(a) return a end");// создать сквозной стиль функции получить функцию из Lua.
1897 sol::function f = lua["f"];
1898
1899 t things = f(t{ 24 });
1900
1901 cout << "things.a: " << things.a << endl;// things.a == 24
1902
1903 return 0;
1904};
1905
1906
1907И это все!
1908
1909Несколько замечаний о реализации: во-первых, есть вспомогательный параметр типа sol :: stack :: record для методов получения и проверки. Это отслеживает, что было выполнено последней завершенной операцией. Так как мы получили 2 члена, мы используем, tracking.use(2);чтобы указать, что мы использовали 2 стековых позиции (одна для bool, одна для int). Второе, на что следует обратить внимание, это то, что мы убедились, что использовали index параметр, а затем приступили к добавлению 1 к нему для следующего.
1910
1911Вы можете сделать что-то подходящее для Lua, но не получить его таким же образом, если специализируете только одну часть системы. Если вам нужно получить его (как возврат, используя одно или несколько значений из Lua), вам следует специализировать sol::stack::getter класс sol::stack::checker шаблона и класс шаблона. Если вам нужно вставить его в Lua в какой-то момент, вам нужно будет специализировать sol::stack::pusher класс шаблона. sol::lua_size Шаблонный класс признак должен быть специализированы для обоих случаев, если это только не отталкивает 1 пункт, в этом случае реализация по умолчанию будет предполагать 1.
1912
1913Заметка
1914
1915Важно отметить , что gett, push и check различие между типом Tи указателем на тип T*. Это означает, что если вы хотите работать чисто, скажем, с T*дескриптором, который не имеет такой же семантики, как просто T, вам может потребоваться указать checkers / getters / pushers для обоих T*и T. Checkers for T*forward to the checkers for T, но получатель for T*не пересылает получателю for T(например, из-за int*того , что он не совсем совпадает с int).
1916
1917В общем, это нормально, так как большинство получателей / контролеров используют только 1 элемента стека. Но, если вы делаете более сложные вложенные классы, было бы полезно использовать, tracking.last чтобы понять, сколько индексов стека выполнила последняя операция gett / check, и увеличить его на единицу после использования вызова. index + tracking.last stack::check<..>( L, index, tracking)
1918
1919Вы можете прочитать больше о самих точках расширения на странице API для стека , и если что-то идет не так или у вас больше есть вопросы, пожалуйста, не стесняйтесь, напишите на странице Github Issues или отправьте электронное письмо!
1920
1921
1922Ошибки.
1923как обрабатывать исключения или другие ошибки
1924Вот несколько советов и приемов для распространенных ошибок об итерации, ошибках компиляции / времени компоновки и других подводных камнях, особенно при работе с исключениями, условиями ошибок и т.п. в sol.
1925
1926Сценарии выполнения.
1927
1928Скрипты могут иметь синтаксические ошибки, могут загружаться из файловой системы неправильно или иметь проблемы во время выполнения. Зная, какой из них может быть неприятным. Существуют различные небольшие строительные блоки для загрузки и запуска кода, но для проверки ошибок вы можете использовать перегруженные функции script / script_file в sol :: state / sol :: state_view , особенно в safe_script вариантах. Они также принимают обратный вызов ошибки, который вызывается только тогда, когда что-то идет не так, и sol поставляется с некоторыми обработчиками ошибок по умолчанию в форме sol::script_default_on_error и sol::script_pass_on_error.
1929
1930Ошибки / предупреждения компилятора.
1931
1932Множество ошибок компиляции может произойти, когда что-то пойдет не так. Вот несколько основных советов по работе с этими типами:
1933Если существует множество ошибок, связанных с index_sequence типами, чертами типов и другими членами, скорее всего, вы не включили свой переключатель C ++ 14 для своего компилятора. Visual Studio 2015 превращает их по умолчанию, но г ++ и лязг ++ не имеют их как значения по умолчанию , и вы должны передать флаг --std=c++1yили --std=c++14, или аналогичный для компилятора.
1934Если вы добавляете в Lua не примитивный тип, вы можете получить странные ошибки в списках инициализаторов или невозможности инициализировать a luaL_Reg. Это может быть связано с автоматической функцией и регистрацией оператора . Отключение может помочь.
1935Иногда сгенерированный тип пользователя может быть очень длинным, если вы связываете много функций-членов. Вы можете получить множество предупреждений об отключении отладочных символов или __LINE_VARпревышении максимальной длины. Вы можете безопасно отключить эти предупреждения для некоторых компиляторов.
1936Ошибки глубины шаблона также могут быть проблемой в более ранних версиях clang ++ и g ++. Используйте -ftemplate-depthфлаг компилятора и укажите действительно большое число (например, 2048 или даже удвоите эту сумму), чтобы позволить компилятору работать свободно.
1937При интенсивном использовании шаблонов пользовательских типов MSVC может вызвать ошибку компилятора C1128 , которая решается с помощью флага компиляции / bigobj .
1938Если у вас есть тип только для перемещения, этот тип может потребоваться, readonlyесли он связан как переменная-член для пользовательского типа или связан с использованием state_view::set_function. Смотрите sol :: readonly для более подробной информации.
1939Назначение stringили использование после его создания может привести к ошибкам компилятора при работе с ним и его результатам. Смотрите эту проблему для исправления этого поведения .pair<T1, T2>operator=sol::function
1940Иногда использование __stdcallв 32-битной (x86) среде на VC ++ может вызвать проблемы с привязкой функций из-за ошибки компилятора. У нас есть исправление prelimanry, но если оно не работает и все еще есть проблемы: поместите функцию в a, functionчтобы ошибки компилятора и другие проблемы исчезли. Также см. Этот отчет о проблеме __stdcall для более подробной информации.
1941Если вы используете /std:c++latestVC ++ и получаете ряд ошибок для noexceptспецификаторов функций, вам, возможно, придется подать проблему или дождаться следующего выпуска компилятора VC ++.
1942Mac OSX Сбои
1943На LuaJIT ваш код может зависать в случайных точках при использовании Mac OSX. Убедитесь, что ваша сборка имеет эти флаги, как рекомендовано на сайте LuaJIT:
1944-pagezero_size 10000 -image_base 100000000
1945Это позволит вашему коду работать правильно, без сбоев. Пожалуйста, прочитайте документацию LuaJIT по компиляции и запуску с LuaJIT для получения дополнительной информации.
1946«Компилятор вне пространства кучи»
1947Типичные Visual Studio, компилятор будет жаловаться , что из кучи пространства , потому что визуальные дефолтов студии с использованием x86 (32-разрядная версия ) версия сама по себе (он все равно будет компилировать x86 или x64 или ARM двоичные файлы, просто компилятор сам является 32-битный исполняемый файл). Чтобы обойти требования к пространству кучи, добавьте в свои .vcoxprojфайлы следующий оператор в соответствии с инструкциями OrfeasZ в этом выпуске :<Import .../>
1948<PropertyGroup>
1949 <PreferredToolArchitecture>x64</PreferredToolArchitecture>
1950</PropertyGroup>
1951При этом следует использовать 64-битные инструменты по умолчанию и увеличить максимальное пространство кучи до того, что может обрабатывать машина с 64-битными окнами. Если у вас не более 4 ГБ ОЗУ или вы все еще сталкиваетесь с проблемами, вам следует изучить использование create_simple_usertypeи добавление функций 1 к 1 , как показано в простом примере типа пользователя здесь ..set( ... )
1952Ошибки компоновщика
1953Есть много причин для ошибок компилятора компилятора. Обычно не знают, что вы скомпилировали библиотеку Lua как C ++: при сборке с C ++ важно отметить, что каждая типичная (статическая или динамическая) библиотека ожидает использования соглашения о вызовах C, и что sol включает код используя, где это применимо.extern 'C'
1954Однако, когда целевая библиотека Lua скомпилирована с C ++, необходимо изменить соглашение о вызовах и схему искажения имен, избавившись от блока. Этого можно достичь, добавив перед включением sol3, или добавив его в командную строку вашей компиляции. Если вы собираете LuaJIT в режиме C ++ (как бы вы этого не знали), то вам тоже нужно . Как правило, нет необходимости использовать этот последний.extern 'C'#defineSOL_USING_CXX_LUA#define SOL_USING_CXX_LUAJIT
1955Обратите внимание, что вы не должны определять их стандартными сборками Lua или LuaJIT. Смотрите страницу конфигурации для более подробной информации.
1956«Пойманные (…) исключения» ошибки
1957Иногда вы ожидаете правильно написанные ошибки и вместо этого получаете ошибку о перехвате ...исключения. Это может означать, что вы либо построили Lua как C ++, либо используете такую среду, как LuaJIT, которая имеет полную поддержку взаимодействия для исключений в определенных типах систем (x64 для LuaJIT 2.0.5, x86 и x64 в LuaJIT 2.1.x-beta и более поздних версиях).
1958Пожалуйста, убедитесь, что используете SOL_EXCEPTIONS_SAFE_PROPAGATIONопределение перед включением sol3, чтобы сделать это. Вы можете прочитать больше на странице исключений здесь .
1959Лови и ломай!
1960По умолчанию sol добавляет default_at_panicобработчик в состояния, открытые sol ( более подробно см. В автоматических обработчиках sol :: state ). Если исключения не отключены, этот обработчик сгенерирует, чтобы дать пользователю шанс на восстановление. Однако почти во всех случаях, когда Lua вызывает lua_atpanicи нажимает эту функцию, это означает, что в вашем коде или коде Lua произошла необратимая ошибка, и виртуальная машина находится в непредсказуемом или мертвом состоянии. Поймать ошибку, выдаваемую из обработчика по умолчанию, и затем действовать так, как будто все исправлено или не в порядке, НЕ лучшая идея. Неожиданные ошибки в оптимизированных сборках и сборках в режиме выпуска могут привести, помимо прочих серьезных проблем.
1961Желательно, если вы поймаете ошибку, в которую войдете, что произошло, завершите работу виртуальной машины Lua как можно скорее, а затем произойдет сбой, если ваше приложение не сможет обработать раскрутку нового состояния Lua. Ловить можно, но вы должны понимать риски того, что вы делаете, когда вы это делаете. Для получения дополнительной информации о перехвате исключений, потенциалах, не отключая исключения и другие хитрости и предостережения, читайте об исключениях в sol здесь .
1962Lua - это прежде всего API C: исключение, возникающее из него, по сути является последним, терминальным поведением, которого виртуальная машина не ожидает. Вы можете увидеть пример обработки паники на странице исключений здесь . Это означает , что создание вокруг незащищенной функции sol3 или вызова сценария является НЕ достаточно , чтобы сохранить виртуальную машину в чистом состоянии. Lua не понимает исключения, и их выдача приводит к неопределенному поведению, если они однажды всплывают через C API, а затем состояние используется снова. Пожалуйста, поймайте, и сбой.try { ... } catch (...) {}
1963Кроме того, для вас было бы хорошей идеей использовать функции безопасности, о которых говорилось в разделе о безопасности , особенно для тех, которые связаны с функциями.
1964Деструкторы и безопасность
1965Другая проблема заключается в том, что Lua - это C API. Он использует setjmpи longjmpвыпрыгивать из кода при возникновении ошибки. Это означает, что он будет игнорировать деструкторы в вашем коде, если вы неправильно используете библиотеку или базовую виртуальную машину Lua. Чтобы решить эту проблему, соберите Lua как C ++. Когда ошибка Lua VM возникает и lua_errorзапускается, она вызывает ее как исключение, которое вызывает правильную семантику раскручивания.
1966Сборка Lua как C ++ позволяет обойти эту проблему и позволяет ошибочно составлять ошибки, генерируемые lua.
1967Защищенные функции и доступ
1968По умолчанию sol :: function предполагает, что код работает нормально и проблем нет. sol :: state (_view) :: script (_file) также предполагает, что код работает нормально. Используйте sol :: protected_function, чтобы получить доступ к функции, где вы можете проверить, все ли работает. Используйте sol :: option для безопасного получения значения из Lua. Используйте sol :: state (_view) :: do_string / do_file / load / load_file для безопасной загрузки и получения результатов из скрипта. Предусмотрены простые и быстрые настройки по умолчанию с исключениями, которые могут привести к аварийному завершению работы виртуальной машины в случае сбоя.
1969
1970Защищенные функции не доступны всем.
1971Иногда некоторые скрипты загружаются плохо. Даже если вы защитите вызов функции, фактическая загрузка файла или его выполнение будут плохими, и в этом случае sol :: protected_function не спасет вас. Убедитесь, что вы зарегистрировали свой собственный обработчик паники, чтобы вы могли отлавливать ошибки, или следуйте советам поведения catch + crash выше. Помните, что вы также можете связать свои собственные функции и отказаться от встроенной защиты sol3 для себя, связав необработанную функцию lua_CFunction
1972
1973Итерация.
1974Таблицы могут иметь другой мусор, который затрудняет итерацию их числовой части при использовании мягкого for-eachцикла или при вызове for_eachфункции sol . Используйте числовой вид для перебора таблицы. Итерация также не повторяется в каком-либо определенном порядке: см. Это примечание в документации таблицы для более подробного объяснения .
1975
1976поддерживаемые компиляторы, двоичный размер, время компиляции получить хороший конечный продукт из соли
1977поддерживаемые компиляторы
1978GCC 7.x теперь отсутствует вместе с Visual Studio 2018. Это означает, что Sol-версия v2.20.1 - это текущая версия кода, предназначенная для более старых компиляторов, не перечисленных ниже. Более новый код будет нацелен на работу со следующими компиляторами и использование их возможностей, возможно, с использованием любых возможностей C ++ 17, предоставляемых компиляторами и стандартными библиотеками, связанными с ними по умолчанию.
1979v2.20.1 поддерживает:
1980VC ++
1981Visual Studio 2018
1982Visual Studio 2015 (последние обновления)
1983GCC (включает MinGW)
1984V7.x
1985v6.x
1986v5.x
1987v4.8 +
1988лязг
1989v4.x
1990v3.9.x
1991v3.8.x
1992v3.7.x
1993v3.6.x
1994Примечание: это относится и к Apple Clang в XCode, но этот компилятор также имеет свои недостатки и проблемы
1995Это не значит, что мы немедленно отказываемся от старых компиляторов. Мы обновим эту страницу, так как соответствующие исправления перенесены в выпуски v2.xx. Помните, что sol3 является полнофункциональным: больше ничего мы не можем добавить в библиотеку на данный момент с поддержкой компилятора C ++ 11 / C ++ 14, так что ваш код будет покрыт еще долго.
1996Новые функции будут нацелены на следующие компиляторы:
1997VC ++
1998Visual Studio vNext
1999Visual Studio 2018
2000GCC (включает MinGW)
2001v8.x
2002V7.x
2003лязг
2004V7.x
2005v6.x
2006v5.x
2007v4.x
2008v3.9.x
2009Обратите внимание, что Visual Studio 2018 Community Edition теперь абсолютно бесплатен и устанавливается быстрее и проще, чем когда-либо прежде. Это также устраняет много хакерских обходных путей и формально поддерживает decltype SFINAE.
2010Версия 7.x компилятора MinGW GCC исправляет давнишний срыв в заголовке <codecvt>, который заменяет порядковые номера строк utf16 и utf32.
2011В Clang 3.4, 3.5 и 3.6 есть много ошибок, с которыми мы сталкивались при разработке sol3 и которые в течение долгого времени отрицательно влияли на пользователей.
2012Мы рекомендуем всем пользователям обновиться немедленно. Если по какой-то причине вам нужен старый код, используйте Sol Release v2.20.1 : в противном случае всегда берите последнюю версию Sol3.
2013поддержка функций
2014Следите за будущим компилятором и поддержкой функций в этом выпуске здесь .
2015поддерживаемая версия Lua
2016Мы поддерживаем:
2017Lua 5.3+
2018Lua 5.2
2019Lua 5.1
2020LuaJIT 2.0.x +
2021LuaJIT 2.1.x-beta3 +
2022двоичные размеры
2023Для индивидов, которые часто используют пользовательские типы, время компиляции может возрасти. Это происходит из-за того, что C ++ 11 и C ++ 14 не имеют очень хороших возможностей для обработки параметров шаблона и переменных параметров шаблона. В C ++ 17 и C ++ Next есть несколько вещей, которые может использовать sol, но проблема в том, что многие люди не могут работать с новейшими и лучшими: поэтому мы должны использовать более старые методы, которые приводят к честному количество избыточных специализаций функций, которые могут зависеть от выбора встраивания компилятора и других подобных методов.
2024улучшения скорости компиляции
2025Вот некоторые заметки о том, как добиться лучшего времени компиляции без ущерба для производительности:
2026Когда вы связываете множество пользовательских типов, поместите их все в одну единицу перевода (один файл C ++), чтобы она не перекомпилировалась несколько раз, а затем будет отброшена компоновщиком позже.
2027Помните, что привязка типа пользователя заканчивается сериализацией в состояние Lua, поэтому вам никогда не нужно, чтобы они появлялись в заголовке и вызывали одинаковые накладные расходы на компиляцию для каждого скомпилированного модуля в вашем проекте.
2028Рассмотрите возможность размещения групп привязок в нескольких разных единицах перевода (нескольких исходных файлах C ++), чтобы при изменении привязок перекомпилировалась только часть привязок.
2029Избегайте помещать привязки в заголовки: он будет замедлять ваш сборник
2030Если вы разрабатываете совместно используемую библиотеку, ограничьте общую площадь поверхности, четко и явно помечая функции как видимые и экспортируемые, а все остальное по умолчанию оставляйте скрытыми или невидимыми.
2031Для людей, у которых уже есть инструмент, который извлекает сигнатуры функций и аргументы, в ваших интересах было бы подключиться к этому инструменту или генератору и выгрузить информацию один раз, используя низкоуровневые абстракции sol3. Вопрос описания предварительных шагов можно найти здесь .
2032следующие шаги
2033Следующим шагом для sol с точки зрения разработчика является формальное превращение библиотеки в C ++ 17. Это будет означать использование выражений складывания и некоторых других вещей, которые значительно сократят время компиляции. К сожалению, это означает также повышение требований к компилятору. Большинству не все равно, другие очень медленно обновляются: найти баланс сложно, и часто нам приходится выбирать обратную совместимость и исправления для плохих / старых компиляторов (которых уже много в базе кода).
2034Надеемся, что по мере развития событий мы продвигаемся вперед.
2035особенности
2036что поддерживает sol (и другие библиотеки)?
2037Цель sol - предоставить невероятно чистый API, который обеспечивает высокую производительность (сравнимую или лучше, чем C, на которой он был написан) и чрезвычайно простую в использовании. То есть пользователи должны иметь возможность сказать: «это работает так, как я ожидал».
2038Для сложных технических компонентов Lua и его экосистемы, которую мы поддерживаем, вот полное изложение:
2039что поддерживает Sol
2040Поддержка Lua 5.1, 5.2 и 5.3+ и LuaJIT 2.0.4 + 2.1.x-beta3 +. Мы достигаем этого через наш заголовок совместимости .
2041Поддержка таблиц : установка значений, получение значений нескольких (разных) типов
2042Ленивая оценка для вложенных / цепочек запросов
2043table["a"]["b"]["c"] = 24;
2044Неявное преобразование в типы, которые вы хотите
2045double b = table["computed_value"];
2046получение поддержки: пометьте функцию, чей возврат должен привести к сопрограмме
2047Дополнительная поддержка: установка значений, получение значений нескольких (разных) типов
2048Ленивая оценка для вложенных / цепочек запросов
2049optional<int> maybe_number = table["a"]["b"]["invalid_key"];
2050Включает безопасность, когда вы этого хотите: скорость, когда вы этого не делаете
2051Поддержка вызовов (функции, лямбды, функции-члены)
2052Вытащите любую функцию Lua с помощью sol :: function :sol::function fx = table["socket_send"];
2053Можно также установить вызываемые элементы в прокси оператора [] :table["move_dude"] = &engine::move_dude;
2054Безопасность: используйте sol :: protected_function, чтобы поймать любую ошибку
2055ЛЮБОЙ вид: исключение C ++ или ошибки Lua перехвачены и проходят через необязательную error_handlerпеременную
2056Дополнительно: перегрузка одного имени функции, поэтому вам не нужно делать скучные проверки типов
2057Дополнительно: эффективная обработка и хорошо документированный способ работы с аргументами
2058Поддержка пользовательского типа ( sol :: usertype в API):
2059Установить функции-члены для вызова
2060Установить переменные-члены
2061Установите переменные в классе, которые основаны на функциях установки / получения, используя свойства
2062Используйте свободные функции, которые принимают Тип в качестве первого аргумента (указатель или ссылка)
2063Поддержка классов «Фабрика», которые не предоставляют конструктор или деструктор
2064Изменение памяти пользовательских данных в C ++ напрямую влияет на Lua без копирования, и
2065Изменение пользовательских данных в Lua напрямую влияет на ссылки / указатели C ++
2066my_class& a = table["a"]; my_class* a_ptr = table["a"];
2067Если вам нужна копия, просто используйте семантику значений и получите копии:
2068my_class a = table["a"];
2069Поддержка потоков / сопрограмм
2070Используйте, возобновляйте и играйте с сопрограммами, как обычные функции
2071Получить и использовать их даже в отдельном потоке Lua
2072Мониторинг статуса и проверка ошибок
2073Дополнительно: настраивается и расширяется под ваши собственные типы, если вы переопределяете определения структуры шаблона getter / pusher / checker .
2074Feature Matrix ™
2075Приведенная ниже таблица характеристик проверяет наличие чего-либо. Это, однако, фактически не учитывает трудоемкий синтаксис.
2076✔ полная поддержка: работает так, как вы ожидаете (оператор [] для таблиц и т. Д.)
2077~ частичная поддержка / поддержка wonky: это означает, что она либо поддерживается другим способом (не с желаемым синтаксисом, серьезными предостережениями и т. д.). Иногда означает отказ от использования простого C API (в какой момент, в чем смысл абстракции?).
2078Support нет поддержки: функция не работает или, если она есть, она ДЕЙСТВИТЕЛЬНО не подходит
2079Замечания по применению библиотек приведены ниже таблиц.
2080объяснения категории
2081Объяснения для нескольких категорий приведены ниже (остальные говорят сами за себя).
2082необязательно: поддержка получения элемента или, возможно, нет (и не форсирование конструкции по умолчанию того, что составляет поддельный / мертвый объект). Обычно приходит с std(::experimental)::optional. Это довольно новый класс, поэтому допустим и внутренний класс внутри библиотеки с похожей семантикой.
2083таблицы: своего рода абстракция для работы с таблицами. Идеальная поддержка есть , и все, что подразумевает синтаксис.mytable["some_key"] =value
2084цепочка таблиц: в сочетании с таблицами, с возможностью глубокого запроса в таблицы mytable["key1"]["key2"]["key3"]. Обратите внимание, что это становится отправной точкой для некоторых библиотек: сбой, если "key1"при попытке доступа не существует "key2"(sol избегает этого специально при использовании sol::optional), и иногда это также является узким местом с высокой производительностью, поскольку выражения не лениво оцениваются библиотекой.
2085произвольные ключи: разрешить коду C ++ использовать пользовательские данные, другие таблицы, целые числа и т. д. в качестве ключей для таблицы.
2086определяемые пользователем типы (udts): типы C ++, данные формы и функции в коде Lua.
2087udts - функции-члены: функции-члены C ++ для типа, обычно вызываемые my_object:foo(1)или похожие в Lua.
2088udts - табличные переменные: переменные / свойства члена C ++, управляемые и в Luamy_object.var = 24
2089Функция привязки: поддержка привязки всех типов функций. Лямбды, функции-члены, свободные функции, в разных контекстах и т. Д.
2090защищенная функция: использование lua_pcallдля вызова функции, которая предлагает обработку ошибок и прыжок на батуте (а также возможность отказаться от этого поведения)
2091multi-return: возвращение нескольких значений из и в Lua (обычно через tuple<...>или каким-либо другим способом)
2092Вариантный / вариантный аргумент: возможность принимать «что угодно» от Lua и даже возвращать «что угодно» Lua ( objectабстракция, вариационные аргументы и т. д.)
2093наследование: допускает некоторую степень подтипирования или наследования классов / пользовательских данных от Lua - это обычно означает, что вы можете извлечь базовый указатель из Lua, даже если вы передадите библиотеке производный указатель
2094перегрузка: способность вызывать перегруженные функции, сопоставленные по арности или типу (тогда lua вызывает другую функцию ).foo( 1 )foo("bark" )
2095Lua thread: базовая оболочка API lua thread; связывает с сопрограммой.
2096сопрограммы: позволяет вызывать функцию несколько раз, возобновляя выполнение сопрограммы Lua каждый раз
2097получение функций C ++: позволяет вызывать функцию из C ++ несколько раз и возвращать любые результаты, которые она возвращает, через C API или в Lua
2098окружения: абстракция для получения, установки и управления средой с использованием табличных методов, функций или иным образом. Обычно для песочницы
2099 обычный C luawrapper Lua-INTF Luabind Селена Sol3 oolua Lua-апи-п.п. Кагуя SLB3 SWIG luacppinterface luwra
2100необязательный ~ ✗ ✔ ✗ ✗ ✔ ✗ ✗ ✔ ✗ ✗ ✗ ✗
2101таблицы ~ ~ ~ ✔ ✔ ✔ ~ ✔ ✔ ✗ ✗ ~ ✔
2102цепочка таблиц ~ ~ ~ ✔ ✔ ✔ ✗ ✔ ✔ ✗ ✗ ~ ✔
2103произвольные ключи ~ ✔ ✔ ✔ ✔ ✔ ✗ ~ ✔ ✗ ✗ ✗ ✗
2104пользовательские типы (udts) ~ ✔ ✔ ✔ ✔ ✔ ~ ✔ ✔ ✔ ✔ ✔ ✔
2105udts: функции-члены ~ ✔ ✔ ✔ ✔ ✔ ~ ✔ ✔ ✔ ✔ ✔ ✔
2106udts: переменные таблицы ~ ~ ~ ~ ~ ✔ ~ ~ ~ ✗ ✔ ✗ ~
2107абстракции стека ~ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ~ ✗ ~ ✔
2108Lua Callables из C (++) ~ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ~
2109привязка функции ~ ✔ ✔ ✔ ✔ ✔ ~ ~ ✔ ~ ~ ~ ✔
2110защищенный вызов ~ ✗ ~ ~ ~ ✔ ~ ✔ ~ ~ ~ ~ ~
2111мульти-возврат ~ ✗ ✔ ✔ ✔ ✔ ~ ✔ ✔ ~ ✔ ~ ✗
2112вариационный / вариантный аргумент ~ ✔ ✔ ✔ ✔ ✔ ~ ✔ ✔ ~ ~ ~ ✗
2113наследование ~ ✔ ✔ ✔ ✔ ✔ ~ ~ ✔ ~ ✔ ~ ✗
2114перегрузка ~ ✗ ✔ ✗ ✗ ✔ ✗ ✗ ✔ ✔ ✔ ✗ ✗
2115Луа нить ~ ✗ ~ ✗ ✗ ✔ ✔ ✗ ✔ ✗ ✗ ✔ ✗
2116окружающая среда ✗ ✗ ✗ ✗ ✗ ✔ ✗ ✗ ✗ ✗ ✗ ✗ ✗
2117сопрограммы ~ ✗ ~ ✔ ✔ ✔ ✗ ✗ ✔ ✗ ✗ ✔ ✗
2118дающие функции C ++ ~ ✔ ✔ ✔ ~ ✔ ~ ✗ ✔ ✗ ~ ✔ ~
2119поддержка no-rtti ✔ ✗ ✔ ✗ ✗ ✔ ✔ ✗ ✔ ✔ ~ ✔ ✔
2120поддержка без исключений ✔ ✗ ✔ ~ ✗ ✔ ✔ ✗ ✔ ✔ ~ ✔ ✔
2121Lua 5.1 ✔ ✔ ✔ ✔ ✗ ✔ ✔ ✔ ✔ ✔ ✔ ✗ ✔
2122Lua 5.2 ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
2123Lua 5.3 ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
2124LuaJIT ✔ ✔ ✔ ✔ ~ ✔ ✔ ✔ ✔ ✔ ✔ ✗ ✔
2125распределение компилировать заголовок и то и другое компилировать заголовок заголовок компилировать компилировать заголовок компилировать генерироваться компилировать заголовок
2126замечания по реализации
2127Обычный C -
2128Очевидно, что вы можете делать все что угодно с Plain C, но прилагаемые усилия являются астрономическими по сравнению с тем, что предлагают другие оболочки, библиотеки и фреймворки.
2129Не очень хорошо масштабируется (с точки зрения простоты использования разработчиком)
2130Компиляция (или использование менеджера пакетов), очевидно, необходима для вашей платформы и требует использования ЛЮБЫХ из этих библиотек, но это нормально, потому что все библиотеки в любом случае нуждаются в некоторой версии Lua, так что у вас всегда есть это!
2131кагуя -
2132Табличные переменные / переменные-члены автоматически превращаются в набор и получениеobj:x( value )obj:x()
2133Имеет дополнительную поддержку
2134Вдохновленная поддержка сопрограмм для sol
2135Автор библиотеки (саторен) хороший парень!
2136C ++ 11/14, или Boosified (что делает его совместимым с C ++ 03)
2137Регистрация классов немного многословна, но не так оскорбительна, как OOLua или lua-intf или другие
2138Синтаксис настройки конструктора выглядит привлекательно
2139соль -
2140Одна из немногих библиотек с дополнительной поддержкой!
2141В основном самый быстрый по всем параметрам: http://sol2.readthedocs.io/en/latest/benchmarks.html
2142Поддержка перегрузки может запутаться с наследованием, см. Здесь
2143Используются флаги C ++ 14 / «C ++ 1y» (-std = c ++ 14, -std = c ++ 1y, = std = c ++ 1z) (доступно с GCC 4.9 и Clang 3.5)
2144Активные вопросы, активные люди
2145Заслуживает много любви!
2146lua-intf -
2147Может быть как заголовочным, так и скомпилированным
2148Имеет дополнительную поддержку
2149C ++ 11
2150Регистрация на основе макросов (странный псевдо-язык)
2151Довольно быстро в большинстве случаев
2152Регистрация классов / «модулей» при использовании кода на C ++ чрезвычайно многословна
2153Чтобы связать поиски в цепочку, нужно склеить ключи (например, "mykey.mykey2") при operator[]поиске (например, вы не можете их произвольно вложить, вы должны предварительно составить правильную строку поиска) (с треском проваливается для поиска не в строке! ).
2154Не так уж и плохо!
2155Селена -
2156Табличные переменные / переменные-члены автоматически превращаются в набор и получениеobj:set_x( value )obj:x()
2157Регистрация классов / «модулей» с использованием кода C ++ очень многословна, похожа на стиль lua-intf
2158Большую часть времени ест дерьмо, когда дело доходит до производительности (см. Тесты )
2159Многие пользователи (посты в блогах и т. Д. Сделали его популярным), но репозиторий довольно застойный ...
2160Luawrapper -
2161Принимает подход написания и чтения таблиц с использованием readVariableи writeVariableфункций
2162C ++ 11, без макросов!
2163Интерфейс может быть неуклюжим (нет табличных структур данных: большинство вещей идет, хотя readVariable/ writeVariable)
2164Внутренние ошибки компилятора в Visual Studio 2015 - отправлен PR, чтобы исправить это, надеюсь, он будет поднят
2165SWIG (3.0) -
2166Очень всеобъемлющий для привязки понятий C ++ (классы, переменные и т. Д.) К Lua
2167Помогает буквально ни с чем другим (таблицы, потоки, абстракции стека и т. Д.)
2168Не очень хорошая, полнофункциональная библиотека ...
2169Требуется этап предварительной обработки (но это не… УЖАСНО сложный этап предварительной обработки); некоторый пример написания дополнительных классов, которые вы уже объявили
2170luacppinterface -
2171В ветке, которая исправляет предупреждения VC ++ и вводит новую работу, есть проблемы с проверкой типов, поэтому используйте только стабильную ветку
2172Нет поддержки табличных переменных
2173На самом деле есть таблицы (но без оператора [])
2174Не поддерживает произвольные ключи
2175Луабинд -
2176Одна из старых фреймворков, но многие обновляют ее и предоставляют «дебошифицированные» версии
2177Странные ключевые слова in-lua и синтаксический анализ, позволяющие писать классы на lua
2178не уверен, что хорошая функция; поставщик привязан к этой библиотеке, чтобы зависеть от этого конкретного синтаксиса класса?
2179Комплексные привязки lua (могут даже связывать «свойства»)
2180Есть некоторый код, который создает ICE в Visual C ++: я отправил исправление в библиотеку в надежде, что оно будет принято
2181Поддержка таблиц Wonky: без базовых функций преобразования luabind::object; нужно нажать объект, а затем использовать lua API, чтобы получить то, что вы хотите
2182Луа-апи-пп -
2183Скомпилировано, но рекомендуется добавлять исходные файлы непосредственно в ваш проект
2184Регистрация пользовательских данных с помощью толстых макросов установки: LUAPP_USERDATA (…) плюс несколько бесплатных функций, которые принимают аргументT& self
2185Вы можете связать функции-члены напрямую, но только если вы переопределяете метатируемые записи
2186В противном случае, СЛОЖНАЯ саморегистрация, которая заставляет задуматься, зачем вы используете фреймворк
2187Вы должны создать контекст, а затем вызвать его, чтобы начать доступ к состоянию lua (добавив больше шаблона… спасибо)
2188К счастью, в отличие от многих библиотек, он на самом деле имеет тип Table, который можно использовать с легкостью. В КОНЦЕ КОНЦОВ
2189C ++ 11-иш в некоторых отношениях
2190Грустное лицо, благодаря способу регистрации пользовательских данных
2191SLB3 -
2192Старый код экспортируется в github из умирающего кода Google
2193«.NET Style» - чтобы переопределить функциональность, наследовать от класса - шаблон (разве это не то, от чего мы пытаемся избавиться?)
2194Указатели повсюду: семантика владения неясна
2195Документация бедных мочой, тьфу!
2196Наверное, наименее любимый для работы!
2197уолу -
2198Синтаксис этой библиотеки не мой любимый ... иди, прочитай документы , решай сам!
2199Наихудшее с точки зрения того, как его использовать: может иметь документы, но DSL чрезвычайно дрянной с толстыми макросами, которые трудно отлаживать / проверять на наличие ошибок
2200Та же проблема, что и у lua-api-pp: нигде не может быть макросов объявления, кроме пространства имен верхнего уровня из-за макроса объявления шаблона
2201Поддерживает отсутствие исключений или RTT включен (блестящий!)
2202Плохая поддержка RAII: стиль default-construct-and-get (требуется некоторая форма инициализации для выполнения getобъекта, и его трудно расширить)
2203Автор библиотеки сообщил мне, что он лично советует людям не использовать Tableабстракцию в OOLua ... Я также советую людям считать ее абстракции таблиц несуществующими?
2204Табличные переменные / переменные-члены из C ++ превращаются в вызовы функций ( get_xи set_xпо умолчанию)
2205Люва -
2206Как вы храните сохраняющие состояние функторы / лямбы? Пока что такой поддержки нет.
2207Невозможно извлечь функции, не оставив их в стеке: ручная очистка становится делом
2208Не понимает functionпреобразования и тому подобное (но с помощью дополнительного кода можно заставить его работать)
2209В последнее время многое улучшено: можно объединять таблицы в таблицы и тому подобное, даже если производительность в этом случае немного огорчает
2210Когда вам удастся установить вызовы функций с помощью макросов, они будут быстрыми (может ли шаблонное решение сделать то же самое? Соль узнает!)
2211Отсутствие поддержки табличных переменных - получите функции getter / setter, похожие на kaguya
2212Табличные переменные становятся классическими статиками (удивительно)
2213Танки в более поздних MSVC
2214
2215compatibility.hpp
2216Совместимость Lua 5.3 / 5.2 для Lua 5.1 / LuaJIT
2217Это подробный заголовок, используемый для обеспечения совместимости с API 5.2 и 5.3+. Он содержит код из MIT-лицензированного кода Lua в некоторых местах, а также из репозитория lua- compat от KeplerProject.
2218Он не полностью документирован, поскольку единственная цель этого заголовка - для внутреннего использования, чтобы убедиться, что sol компилируется на всех платформах / дистрибутивах без ошибок или отсутствующих функциональных возможностей Lua. Если вы считаете, что есть какие-то функции совместимости, которых нам не хватает, или если вы сталкиваетесь с ошибками переопределения, внесите ошибку в систему отслеживания ошибок .
2219Если у вас это уже есть в вашем проекте или у вас есть собственный уровень совместимости, то перед включением или передачей этого флага в командной строке отключите упаковщик совместимости.#define SOL_NO_COMPAT 1sol.hpp
2220Для лицензий, смотрите здесь
2221легкий <T> / пользователь <T>
2222служебный класс для самой дешевой формы (легких) пользовательских данных
2223
2224template <typename T>
2225struct user;
2226
2227template <typename T>
2228struct light;
2229sol::user<T>и sol::light<T>два служебных класса, которые не участвуют в полной системе sol :: usertype <T> . Цель этих классов - обеспечить минимальный объем памяти и накладные расходы для размещения одного элемента и получения одного элемента из Lua. sol::user<T>при нажатии на Lua создаст тонкий, безымянный metatable для этого экземпляра, в частности, для вызова его деструктора. sol::light<T>специально толкает ссылку / указатель на Lua как sol::type::lightuserdata.
2230
2231Если вы чувствуете, что вам не нужно, чтобы что-то участвовало в полной системе пользовательских типов <T> , используйте служебные функции и для создания этих типов и сохранения их в Lua. Вы можете получить их стек Lua / из системы Lua, используя те же методы извлечения на и на столах и с операциями стека.sol::make_user( ... )sol::make_light( ... )getoperator[]
2232
2233Оба имеют неявные операторы преобразования в T*и T&, так что вы можете сразу установить для них соответствующие указатели и ссылочные типы, если они вам нужны.
2234пространство имен стека
2235слой абстракции нитро-песчаного ядра над Lua
2236
2237namespace stack
2238Если вы обнаружите, что абстракции более высокого уровня не соответствуют вашим потребностям, вы, возможно, захотите углубиться в stack пространство имен, чтобы попытаться получить больше от sol. stack.hpp а stack пространство имен определяет несколько утилит для работы с Lua, включая утилиты push / popping, геттеры, средства проверки типов, помощники вызовов Lua и многое другое. Это пространство имен не документировано полностью, так как большая часть его интерфейса является ртутной и может меняться между выпусками, либо сильно повышать производительность, либо улучшать sol api .
2239
2240Работу на этом уровне стека можно улучшить, если понять, как работает стек Lua в целом, а затем дополнить его объектами и предметами.
2241
2242Однако есть несколько точек настройки ADL, которые вы можете использовать для своих целей, и несколько потенциально полезных функций. Это может помочь, если вы пытаетесь уменьшить объем кода, который вам нужно написать, или если вы хотите, чтобы ваши типы по-разному вели себя в стеке sol. Обратите внимание, что переопределение значений по умолчанию может привести к отказу от многих гарантий безопасности, которые предоставляет sol: поэтому изменяйте точки расширения по своему усмотрению.
2243
2244структуры
2245структура: запись
2246struct record {
2247 int last;
2248 int used;
2249
2250 void use(int count);
2251};
2252Эта структура предназначена для расширенного использования с stack :: get и stack :: check_get . При переопределении точек настройки важно вызвать useфункцию-член этого класса с количеством вещей, которые вы вытаскиваете из стека. usedсодержит общее накопление произведенных предметов. lastэто количество элементов, полученных из стека с последней операцией (не обязательно извлеченных из стека). Во всех тривиальных случаях для типов и после операции; структуры, такие как и могут тянуть больше в зависимости от классов, которые он содержит.last == 1used == 1pairtuple
2253
2254При переопределении точек настройки обратите внимание, что эта структура должна позволять вам помещать несколько возвращаемых значений и получать несколько возвращаемых значений в стек, и, таким образом, иметь возможность беспрепятственно упаковать / распаковать возвращаемые значения из Lua в одну структуру C ++ и наоборот. наоборот. Эта функция рекомендуется только для людей, которым необходимо настроить библиотеку дальше, чем основы. Это также хороший способ добавить поддержку для типа и предложить его обратно в исходную библиотеку, чтобы другие могли получить пользу от вашей работы.
2255
2256Обратите внимание, что настройки также можно разместить здесь на отдельной странице, если отдельные лица решат сделать детальные настройки для своей структуры или других мест.
2257
2258структура: зонд
2259struct probe {
2260 bool success;
2261 int levels;
2262
2263 probe(bool s, int l);
2264 operator bool() const;
2265};
2266Эта структура используется для того, чтобы показать, было ли успешное исследование get_field или нет.
2267
2268члены
2269функция: call_lua
2270template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
2271inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs);
2272Эта функция полезна, когда вы связываете к сырому функции C , но нужны абстракции SOL, чтобы спасти вас агонию настройки аргументов и знать , как вызов функций C работает . startПараметр указывает функцию , где начать вытягивать аргументы. Параметр fx - это то, что должно называться. Дополнительные аргументы передаются функции напрямую. Существуют промежуточные версии этого ( sol::stack::call_into_luaи аналогичного) для более продвинутых пользователей, но они не документированы, поскольку они могут быть изменены для повышения производительности или соответствующей корректировки API в последующих итерациях sol3. Используйте более продвинутые версии на свой страх и риск.
2273
2274функция: получить
2275template <typename T>
2276auto get( lua_State* L, int index = -1 )
2277template <typename T>
2278auto get( lua_State* L, int index, record& tracking )
2279Получает значение объекта indexв стеке. Тип возвращаемого значения зависит от T: с примитивными типами обычно это так T: для всех нераспознанных Tэто, как правило, T&точка расширения, возвращаемая реализацией sol_lua_get <T> . Тип Tпроверяется один раз, как есть (с constоставленными в покое и ссылочными квалификаторами), а затем еще раз, когда он удаляетconst квалификаторы верхнего уровня и модификаторы ссылок, прежде чем перенаправлять их в функцию sol_lua_get <T> точки расширения . stack::getпо умолчанию будет пересылать все аргументы в функцию stack :: check_get с обработчиком, type_panicчтобы сильно предупреждать об ошибках, если вы просите о безопасности,
2280
2281Вы также можете извлечь sol :: необязательный <T> из этого, чтобы он пытался не выдавать ошибки при выполнении get, а тип неверный.
2282
2283функция: проверить
2284template <typename T>
2285bool check( lua_State* L, int index = -1 )
2286
2287template <typename T, typename Handler>
2288bool check( lua_State* L, int index, Handler&& handler )
2289
2290template <typename T, typename Handler>
2291bool check( lua_State* L, int index, Handler&& handler, record& tracking )
2292Проверяет, имеет ли объект indexтип T. Если это не так , он будет вызывать handlerфункцию с , , и в качестве аргументов (и , возможно , с 5 - го аргумента строки . Если вы не передаете свой собственный обработчик, обработчик будет пройдена.lua_State* Lint indexsol::type expectedsol::type actualsol::string_view messageno_panic
2293
2294функция: get_usertype
2295template <typename T>
2296auto get_usertype( lua_State* L, int index = -1 )
2297template <typename T>
2298auto get_usertype( lua_State* L, int index, record& tracking )
2299Непосредственно пытается повторно получить тип, Tиспользуя механизмы пользовательского типа sol3. Аналогично обычному getдля определенного пользователем типа. Полезно, когда вам нужно получить доступ к механизму получения пользовательских типов в sol3 и в то же время обеспечить собственную настройку .
2300
2301функция: check_usertype
2302template <typename T>
2303bool check_usertype( lua_State* L, int index = -1 )
2304
2305template <typename T, typename Handler>
2306bool check_usertype( lua_State* L, int index, Handler&& handler )
2307
2308template <typename T, typename Handler>
2309bool check_usertype( lua_State* L, int index, Handler&& handler, record& tracking )
2310Проверяет, имеет ли объект at indexтип Tи сохраняется ли он как пользовательский тип sol3. Полезно, когда вам нужно получить доступ к механизму проверки пользовательских типов sol3, в то же время предоставляя свои собственные настройки .
2311
2312функция: check_get
2313template <typename T>
2314auto check_get( lua_State* L, int index = -1 )
2315template <typename T, typename Handler>
2316auto check_get( lua_State* L, int index, Handler&& handler, record& tracking )
2317Получает значение объекта indexв стеке, но делает это безопасно. Возвращает optional<U>, где Uв данном случае это тип возвращаемого значения stack::get<T>. Это позволяет человеку должным образом проверить, является ли тип, который он получает, тем, что он на самом деле хочет, и изящно обрабатывать ошибки при работе со стеком, если он того пожелает. Вы можете SOL_ALL_SAFETIES_ONвключить дополнительную безопасность , в которой по stack::getумолчанию будет вызываться эта версия функции с некоторым вариантом обработчика, sol::type_panic_stringчтобы сильно предупреждать об ошибках и помогать вам отслеживать ошибки, если вы подозреваете, что в вашей системе что-то идет не так.
2318
2319функция: нажать
2320// push T inferred from call site, pass args... through to extension point
2321template <typename T, typename... Args>
2322int push( lua_State* L, T&& item, Args&&... args )
2323
2324// push T that is explicitly specified, pass args... through to extension point
2325template <typename T, typename Arg, typename... Args>
2326int push( lua_State* L, Arg&& arg, Args&&... args )
2327
2328// recursively call the the above "push" with T inferred, one for each argument
2329template <typename... Args>
2330int multi_push( lua_State* L, Args&&... args )
2331Основываясь на том, как он вызывается, помещает в стек переменное количество объектов. в 99% случаев возвращает 1 объект, помещенный в стек. В случае a tuple<...>он рекурсивно выталкивает каждый объект, содержащийся в кортеже, слева направо, в результате чего в стек помещается переменное число вещей (это позволяет многозначные возвраты при привязке функции C ++ к Lua). Может вызываться с аргументами, отличающимися от типа, который хочет выдвинуть, или откуда будет выведен вывод . Окончательная форма этой функции , которая будет вызывать один для каждого аргумента. То, что описывает то, что нажать, сначала очищается путем удаления верхнего уровня.sol::stack::push<T>( L, args... )sol::stack::push( L, arg, args... )Targsol::stack::multi_pushsol::stack::pushTconstквалификаторы и эталонные квалификаторы перед отправкой в точку расширения sol_lua_push <T> .
2332
2333функция: push_reference
2334// push T inferred from call site, pass args... through to extension point
2335template <typename T, typename... Args>
2336int push_reference( lua_State* L, T&& item, Args&&... args )
2337
2338// push T that is explicitly specified, pass args... through to extension point
2339template <typename T, typename Arg, typename... Args>
2340int push_reference( lua_State* L, Arg&& arg, Args&&... args )
2341
2342// recursively call the the above "push" with T inferred, one for each argument
2343template <typename... Args>
2344int multi_push_reference( lua_State* L, Args&&... args )
2345Эти функции ведут себя аналогично приведенным выше, но они проверяют определенные критерии и вместо этого пытаются выдвинуть ссылку, а не принудительно копировать копию, если это необходимо. Используйте его осторожно, так как sol3 использует это главным образом как возврат из функций и переменных пользовательского типа, чтобы сохранить семантику цепочки / переменной от этого объекта класса. Его внутренние компоненты обновляются в соответствии с потребностями sol3, и, хотя он, как правило, делает «правильные вещи» и его не нужно менять какое-то время, sol3 оставляет за собой право изменять свои внутренние механизмы обнаружения в соответствии с потребностями своих пользователей в любое время, как правило, без нарушения обратной совместимости и ожиданий, но не совсем гарантировано.
2346
2347функция: поп
2348template <typename... Args>
2349auto pop( lua_State* L );
2350Выталкивает объект из стека Удалит фиксированное количество объектов из стека, как правило, определяется sol::lua_size<T>чертами предоставленных аргументов. Обычно это функция простоты, используемая для удобства.
2351
2352функция: верх
2353int top( lua_State* L );
2354Возвращает количество значений в стеке.
2355
2356функция: set_field
2357template <bool global = false, typename Key, typename Value>
2358void set_field( lua_State* L, Key&& k, Value&& v );
2359
2360template <bool global = false, typename Key, typename Value>
2361void set_field( lua_State* L, Key&& k, Value&& v, int objectindex);
2362Устанавливает поле, на которое ссылается ключ, kна заданное значение v, помещая ключ в стек, помещая значение в стек, а затем выполняя эквивалент lua_setfieldобъекта для данного значения objectindex. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
2363
2364функция: get_field
2365template <bool global = false, typename Key>
2366void get_field( lua_State* L, Key&& k [, int objectindex] );
2367Получает поле, на которое ссылается ключ k, путем нажатия ключа на стек и затем выполнения эквивалента lua_getfield. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
2368
2369Эта функция оставляет полученное значение в стеке.
2370
2371функция: probe_get_field
2372template <bool global = false, typename Key>
2373probe probe_get_field( lua_State* L, Key&& k [, int objectindex] );
2374Получает поле, на которое ссылается ключ k, путем нажатия ключа на стек и затем выполнения эквивалента lua_getfield. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный. Кроме того, он делает это безопасно, входя только на столько уровней, насколько это возможно: если возвращаемое значение не является чем-то, что может быть проиндексировано, тогда запросы обхода с tuple/ pairпрекратят работу раньше и вернут зондирующую информацию со структурой зонда .
2375
2376Эта функция оставляет полученное значение в стеке.
2377
2378объекты (точки расширения)
2379Вы можете настроить способ, которым sol обрабатывает различные структуры и классы, следуя информации, представленной в добавлении ваших собственных типов .
2380
2381Ниже приведена более обширная информация для любознательных.
2382
2383Точка расширения ADL sol_lua_get
2384MyType sol_lua_get ( sol::types<MyType>, lua_State* L, int index, sol::stack::record& tracking ) {
2385 // do work
2386 // ...
2387
2388 return MyType{}; // return value
2389}
2390Эта точка расширения относится к getобъекту (или ссылке, или указателю, или какому-либо другому) типа Tили к чему-то, что может быть преобразовано в него. Внутренняя реализация getter по умолчанию предполагает, Tчто это тип пользователя, и извлекает данные пользователя из Lua, прежде чем пытаться привести их к желаемому T.
2391
2392В целом, есть реализации для получения чисел (типа is_floating, is_integralсовпадающих по типу), получения stringи добавления широких строковых и юникодных вариантов, получения необработанных пользовательских данных с помощью userdata_value и чего угодно, как upvalues с upvalue_index , получения необработанных lua_CFunction s и, наконец, извлечения функций Lua в . Он также определен для всего, что происходит от sol :: reference . У этого также есть специальная реализация для 2 умных указателей стандартной библиотеки (см. Память типа пользователя ), которая может быть более конкретно расширена.const char*function<R(Args...)>
2393
2394Точка расширения ADL sol_lua_push
2395int push ( sol::types<MyType>, lua_State* L, MyType&& value ) {
2396 // can optionally take more than just 1 argument
2397 // to "construct" in-place and similar
2398 // use them however you like!
2399 // ...
2400 return N; // number of things pushed onto the stack
2401}
2402Эта точка расширения является pushзначением в Lua. Возвращает количество вещей, помещенных в стек. Реализация по умолчанию предполагает, Tчто это пользовательский тип, и помещает пользовательские данные в Lua с привязкой к ним специфической для класса метатаблицы в масштабе штата. Есть реализации толкания чисел ( is_floating, is_integralСопоставления типов), получение stringи , получая сырой UserData с UserData и сырьем upvalues с повышать стоимость , получая сырой lua_CFunction с, и , наконец , вытаскивая функцию Lua в . Он также определен для всего, что происходит от sol :: reference . У этого также есть специальная реализация для 2 умных указателей стандартной библиотеки (см. Память типа пользователя)const char*sol::function).
2403
2404Точка расширения ADL sol_lua_check
2405template <typename Handler>
2406bool sol_lua_check ( sol::types<MyType>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking ) {
2407 // if the object in the Lua stack at index is a T, return true
2408 if ( ... ) {
2409 tracking.use(1); // or however many you use
2410 return true;
2411 }
2412 // otherwise, call the handler function,
2413 // with the required 4/5 arguments, then return false
2414 //
2415 handler(L, index, expected, indextype, "message");
2416 return false;
2417}
2418Эта точка расширения заключается в checkтом, является ли тип по данному индексу тем, чем он должен быть. Реализация по умолчанию просто проверяет, равен ли ожидаемый тип, переданный через шаблон, типу объекта по указанному индексу в стеке Lua. Реализация по умолчанию для типов, которые рассматриваются, userdataпроходит множество проверок, чтобы поддержать проверку, является ли тип действительно типом Tили является ли он базовым классом того, что он на самом деле хранит как пользовательские данные в этом индексе.
2419
2420Обратите внимание, что вы можете
2421
2422Точка расширения ADL sol_lua_interop_check
2423template <typename T, typename Handler>
2424bool sol_lua_interop_check(sol::types<T>, lua_State* L, int relindex, sol::type index_type, Handler&& handler, sol::stack::record& tracking) {
2425 // implement custom checking here for a userdata:
2426 // if it doesn't match, return "false" and regular
2427 // sol userdata checks will kick in
2428 return false;
2429 // returning true will skip sol's
2430 // default checks
2431}
2432Эта точка расширения предназначена для checkвнешних пользовательских данных. Он должен возвращаться, trueесли тип соответствует некоторой пользовательской спецификации пользовательских данных (скажем, из другой библиотеки или внутренней структуры), и falseесли нет. Реализация по умолчанию просто возвращается, falseчтобы позволить исходным обработчикам sol3 позаботиться обо всем. Если вы хотите реализовать свою собственную проверку пользовательских типов; например, для возни с toLuaили OOLuaили kaguyaили некоторыми другими библиотеками. Обратите внимание, что библиотека должна иметь макет с совместимой памятью, если вы хотите специализировать этот метод проверки, но не последующий метод получения . Вы можете специализировать его, как показано в примерах взаимодействия .
2433
2434Заметка
2435
2436Вы должны включить эту функцию с помощью SOL_ENABLE_INTEROP, как описано в разделе конфигурации и безопасности .
2437
2438Точка расширения ADL sol_lua_interop_get
2439template <typename T>
2440pair<bool, T*> sol_lua_interop_get(sol::types<T> t, lua_State* L, int relindex, void* unadjusted_pointer, sol::stack::record& tracking) {
2441 // implement custom getting here for non-sol3 userdatas:
2442 // if it doesn't match, return "false" and regular
2443 // sol userdata getters will kick in
2444 return { false, nullptr };
2445}
2446Эта точка расширения относится к getсторонним данным пользователя. Он должен возвращать оба trueи настроенный указатель, если тип соответствует некоторой пользовательской спецификации пользовательских данных (скажем, из другой библиотеки или внутренней структуры). Реализация по умолчанию просто возвращается, чтобы позволить стандартной реализации sol3 позаботиться обо всем. Вы можете использовать его для взаимодействия с другими платформами, которые не являются sol3, но все еще включают их силу; например, для возни с или некоторых других библиотек. Вы можете специализировать его, как показано в примерах взаимодействия .{ false, nullptr }kaguya
2447
2448Заметка
2449
2450Вы должны включить его с помощью SOL_ENABLE_INTEROP, как описано в разделе конфигурации и безопасности .
2451
2452Заметка
2453
2454Вам НЕ нужно использовать этот метод, в частности, если расположение памяти совместимо. (Например, toLuaхранит пользовательские данные в sol3-совместимом способе.)
2455
2456решить
2457утилита для выбора перегруженных вызовов функций C ++
2458
2459функция: разрешить перегрузку C ++
2460template <typename... Args, typename F>
2461constexpr auto resolve( F f );
2462resolveэто функция, которая предназначена для того, чтобы помочь пользователям выбрать одну функцию из группы перегруженных функций в C ++. Он работает как для членских, так и для свободных функций. Вы можете использовать его для выбора перегрузок, указав сигнатуру в качестве первого аргумента шаблона. Дан набор перегруженных функций:
2463
2464int overloaded(int x);
2465int overloaded(int x, int y);
2466int overloaded(int x, int y, int z);
2467
2468struct thing {
2469 int overloaded() const;
2470 int overloaded(int x);
2471 int overloaded(int x, int y);
2472 int overloaded(int x, int y, int z);
2473};
2474Вы можете устранить их неоднозначность, используя resolve:
2475
2476auto one_argument_func = resolve<int(int)>( overloaded );
2477auto two_argument_func = resolve<int(int, int)>( overloaded );
2478auto three_argument_func = resolve<int(int, int, int)>( overloaded );
2479auto member_three_argument_func = resolve<int(int, int, int)>( &thing::overloaded );
2480auto member_zero_argument_const_func = resolve<int() const>( &thing::overloaded );
2481Это важно отметить , что constпомещается в конце для того, когда вы хотите константные перегрузки. Вы получите ошибки компилятора, если вы не конкретизируете и не устраните неоднозначность для функций-членов const. Это разрешение также становится полезным при установке функций для таблицы или state_view :
2482
2483
2484sol::state lua;
2485
2486lua.set_function("a", resolve<int(int)>( overloaded ) );
2487lua.set_function("b", resolve<int(int, int)>( overloaded ));
2488lua.set_function("c", resolve<int(int, int, int)>( overloaded ));
2489Его также можно использовать с sol :: c_call :
2490
2491
2492sol::state lua;
2493
2494auto f = sol::c_call<
2495 decltype(sol::resolve<int(int, int)>(&overloaded)),
2496 sol::resolve<int(int, int)>(&overloaded)
2497>;
2498lua.set_function("f", f);
2499
2500lua.script("f(1, 2)");
2501Заметка
2502
2503Вы не можете использовать, sol::resolve<...>(...)когда одна функция является шаблонной, и у нее есть перегрузка без шаблонов: в этом случае она всегда будет неудачной. Чтобы решить эту проблему, используйте руководство или (с необходимыми квалификаторами const -ess, volatile-ness и r-value / l-value, если необходимо).static_cast<R(Args...)>( &func )static_cast<R (T::*)(Args...)>( &T::overloaded_member_func )
2504
2505c_call
2506шаблонный тип для передачи функций через шаблоны
2507
2508template <typename Function, Function f>
2509int c_call (lua_State* L);
2510
2511template <typename... Functions>
2512int c_call (lua_State* L);
2513Цель sol::c_call<...>состоит в том, чтобы предоставить способ обернуть функцию и транспортировать ее в контексте времени компиляции. Это обеспечивает более быструю скорость за счет гораздо более сложного для чтения / ухудшения интерфейса и может уменьшить некоторые проблемы со скоростью компиляции шаблонов. sol::c_callожидает тип для своего первого аргумента шаблона и значение ранее предоставленного типа для второго аргумента шаблона. Чтобы сделать перегруженную функцию во время компиляции, укажите несколько функций в одной и той же паре, но поместите ее в a .type, valuesol::wrap
2514
2515Заметка
2516
2517Это также может быть помещено в список аргументов для пользовательского типа .
2518
2519Это выталкивает необработанные данные lua_CFunctionво все c_callобъекты, в которые вы передаете указатель результирующей функции, будь то таблица, пользовательские данные или что-либо еще, использующее API sol3. Полученный результат lua_CFunctionтакже можно использовать непосредственно с API lua, точно так же, как многие типы sol3 могут смешиваться с API Lua, если вы знаете, что делаете.
2520
2521Желательно, чтобы пользователь рассмотрел возможность создания макроса для выполнения необходимых действий . Sol не предоставляет один, потому что многие кодовые базы уже имеют один подобный этому .decltype( &function_name, ), function_name
2522
2523Ниже приведен пример различных способов использования sol::c_call:
2524
2525#define SOL_ALL_SAFETIES_ON 1
2526#include <sol/sol.hpp>
2527
2528#include "assert.hpp"
2529
2530int f1(int) { return 32; }
2531
2532int f2(int, int) { return 1; }
2533
2534struct fer {
2535 double f3(int, int) {
2536 return 2.5;
2537 }
2538};
2539
2540
2541int main() {
2542
2543 sol::state lua;
2544 // overloaded function f
2545 lua.set("f", sol::c_call<sol::wrap<decltype(&f1), &f1>, sol::wrap<decltype(&f2), &f2>, sol::wrap<decltype(&fer::f3), &fer::f3>>);
2546 // singly-wrapped function
2547 lua.set("g", sol::c_call<sol::wrap<decltype(&f1), &f1>>);
2548 // without the 'sol::wrap' boilerplate
2549 lua.set("h", sol::c_call<decltype(&f2), &f2>);
2550 // object used for the 'fer' member function call
2551 lua.set("obj", fer());
2552
2553 // call them like any other bound function
2554 lua.script("r1 = f(1)");
2555 lua.script("r2 = f(1, 2)");
2556 lua.script("r3 = f(obj, 1, 2)");
2557 lua.script("r4 = g(1)");
2558 lua.script("r5 = h(1, 2)");
2559
2560 // get the results and see
2561 // if it worked out
2562 int r1 = lua["r1"];
2563 c_assert(r1 == 32);
2564 int r2 = lua["r2"];
2565 c_assert(r2 == 1);
2566 double r3 = lua["r3"];
2567 c_assert(r3 == 2.5);
2568 int r4 = lua["r4"];
2569 c_assert(r4 == 32);
2570 int r5 = lua["r5"];
2571 c_assert(r5 == 1);
2572
2573 return 0;
2574}
2575« As_function :: Содержание :: разрешение »
2576as_function
2577убедитесь, что объект выдвинут как функция
2578
2579template <typename Sig = sol::function_sig<>, typename... Args>
2580function_argumants<Sig, Args...> as_function ( Args&& ... );
2581Эта функция предназначена для того, чтобы гарантировать, что вызываемая структура (например, лямбда) может быть передана вызовам sol :: table и обрабатываться как привязка функции вместо пользовательских данных. Рекомендуется вместо этого использовать вызов sol :: table :: set_function , но если по какой-то причине его нужно использовать , то это поможет гарантировать, что вызываемая структура обрабатывается как лямбда / вызываемая, а не просто как структура пользовательских данных.set( key, value )setas_function
2582
2583Этот класс также может сделать так, чтобы пользовательские типы связывали типы переменных как функции для привязок пользовательских типов.
2584
2585#define SOL_ALL_SAFETIES_ON 1
2586#include <sol/sol.hpp>
2587
2588int main () {
2589 struct callable {
2590 int operator()( int a, bool b ) {
2591 return a + (b ? 10 : 20);
2592 }
2593 };
2594
2595
2596 sol::state lua;
2597 // Binds struct as userdata
2598 // can still be callable, but beware
2599 // caveats
2600 lua.set( "not_func", callable() );
2601 // Binds struct as function
2602 lua.set( "func", sol::as_function( callable() ) );
2603 // equivalent: lua.set_function( "func", callable() );
2604 // equivalent: lua["func"] = callable();
2605}
2606Обратите внимание, что если вы действительно хотите, чтобы пользовательские данные были доступны для вызова , вам просто нужно создать sol :: table :: new_usertype и затем привязать "__call"метаметод (или просто использовать sol::meta_function::call перечисление ). Это может или не может быть сделано автоматически для вас, в зависимости от того, перегружен ли оператор вызова и тому подобное.
2607
2608Вот пример привязки переменной как функции к типу пользователя:
2609
2610#define SOL_ALL_SAFETIES_ON 1
2611#include <sol/sol.hpp>
2612
2613int main () {
2614 class B {
2615 public:
2616 int bvar = 24;
2617 };
2618
2619 sol::state lua;
2620 lua.open_libraries(sol::lib::base);
2621 lua.new_usertype<B>("B",
2622 // bind as variable
2623 "b", &B::bvar,
2624 // bind as function
2625 "f", sol::as_function(&B::bvar)
2626 );
2627
2628 B b;
2629 lua.set("b", &b);
2630 lua.script(R"(x = b:f()
2631 y = b.b
2632 assert(x == 24)
2633 assert(y == 24)
2634 )");
2635
2636 return 0;
2637}
2638« Только для чтения :: Содержание :: c_call »
2639только для чтения
2640подпрограмма, чтобы пометить переменную-член только для чтения
2641
2642template <typename T>
2643auto readonly( T&& value );
2644Цель только для чтения - защитить набор переменных для типа пользователя или функции. Просто оберните его вокруг переменной-члена, например, в соответствующем месте, чтобы использовать его. Если кто-то попытается установить его, он ошибется своим кодом.sol::readonly( &my_class::my_member_variable )
2645
2646sol::readonlyЭто особенно важно, когда вы работаете с типами, которые не имеют конструктора копирования. Lua не понимает семантику перемещения, и поэтому для установщиков пользовательских типов требуется конструктор копирования C ++. Контейнеры как переменные-члены, которые содержат типы, которые не являются копируемыми, но могут быть перемещены - например, vector<my_move_only_type>среди других - также могут ошибочно утверждать, что они являются копируемыми, но терпят неудачу с ошибками компилятора. Если ваш тип не соответствует определению контейнера как подлежащего копированию или просто не подлежит копированию в целом, и это переменная-член, пожалуйста, используйте sol::readonly.
2647
2648Если вы хотите создать таблицу только для чтения, вам нужно пройти через сложную песню и танец, переопределив __indexметаметод. Вот полный пример того, как это сделать, используя sol:
2649
2650read_only.cpp
2651
2652#define SOL_ALL_SAFETIES_ON 1
2653#include <sol/sol.hpp>
2654
2655#include <iostream>
2656
2657struct object {
2658 void my_func() {
2659 cout << "hello\n";
2660 }
2661};
2662
2663int deny(lua_State* L) {
2664 return luaL_error(L, "HAH! Deniiiiied!");
2665}
2666
2667int main(int, char*[]) {
2668
2669 sol::state lua;
2670 lua.open_libraries(sol::lib::base);
2671
2672 object my_obj;
2673
2674 sol::table obj_table = lua.create_named_table("object");
2675
2676 sol::table obj_metatable = lua.create_table_with();
2677 obj_metatable.set_function("my_func", &object::my_func, &my_obj);
2678 // Set whatever else you need to
2679 // on the obj_metatable,
2680 // not on the obj_table itself!
2681
2682 // Properly self-index metatable to block things
2683 obj_metatable[sol::meta_function::new_index] = deny;
2684 obj_metatable[sol::meta_function::index] = obj_metatable;
2685
2686 // Set it on the actual table
2687 obj_table[sol::metatable_key] = obj_metatable;
2688
2689 try {
2690 lua.script(R"(
2691print(object.my_func)
2692object["my_func"] = 24
2693print(object.my_func)
2694 )");
2695 }
2696 catch (const exception& e) {
2697 cout << "an expected error occurred: " << e.what() << endl;
2698 }
2699 return 0;
2700}
2701Это подробный пример, но он все объясняет. Поскольку этот процесс немного сложен и может иметь неожиданные последствия для пользователей, которые создают свои собственные таблицы, создание таблиц только для чтения - это то, что мы просим пользователей сделать с помощью приведенного выше кода, так как семантика подходит для десятков использования. случаи были бы чрезвычайно сложными.
2702
2703политика
2704изменение стека непосредственно перед возвратом вызова lua
2705
2706sol::policiesэто продвинутая функция низкоуровневой модификации, позволяющая вам использовать преимущества абстракций sol3 перед применением ваших собственных стековых модификаций в последний момент. Они охватывают ту же функциональность, что и типы luabind «return reference» и «зависимости» . Для вашего использования определены несколько предварительно настроенных политик:
2707
2708политика использование модификация
2709sol::returns_self sol::policies( some_function, sol::returns_self() )
2710принимает аргумент в стеке с индексом 1 ( selfв вызовах функций-членов и лямбда-выражениях, которые вначале принимают определенные пользовательские данные) и делает его возвращаемым значением
2711вместо того, чтобы создавать новые пользовательские данные, которые ссылаются на ту же память C ++, он копирует пользовательские данные, подобно записи просто увеличивает счетчик ссылокobj2 = obj1
2712экономит пространство памяти поверх сохранения оригинальной памяти
2713sol::returns_self_with<int...> sol::policies( some_function, sol::returns_self_with<2, 3>() )
2714то же самое, что и выше, с предупреждением, selfкоторое возвращается, в то же время помещая зависимости вself
2715может поддерживать внешние зависимости
2716sol::self_dependency sol::policies( some_function, sol::self_dependency() );
2717это делает значение, возвращаемое связываемым объектом, зависимым от selfаргумента
2718полезно для возврата ссылки на переменную-член и поддержания живого родительского класса этой переменной-члена
2719sol::stack_dependencies sol::policies( some_function, sol::stack_dependencies( target_index, 2, 1, ... ) );
2720все, что находится в target_indexстеке, получает специальную таблицу «keep alive» с элементами в стеке, указанными целочисленными индексами послеtarget_index
2721позволяет поддерживать аргументы и другие вещи в течение всего времени существования класса
2722обычай sol::policies( some_function, [](lua_State* L, int current_stack_return_count) -> int { ... } )
2723все, что вы хотите, пока оно имеет форму int (lua_State*, int )
2724работает с вызываемыми элементами (такими как лямбды), если они имеют правильную форму
2725ожидается вернуть количество вещей в стеке, чтобы вернуться к Lua
2726«Some_function» может быть любой вызываемой функцией, переменной-членом или подобным
2727дополнения зависимостей работают только на пользовательских данных
2728работает с , и на всех привязках пользовательских типовtable::set( ... )table::set_function( ... );
2729Вы можете указать несколько политик для одного sol::policiesвызова, а также указать пользовательские политики, если подпись верна.
2730
2731« Protect :: Contents :: readonly »
2732защитить
2733подпрограмма для обозначения функции / переменной как требующей безопасности
2734
2735template <typename T>
2736auto protect( T&& value );
2737sol::protect( my_func )позволяет защитить вызов функции или переменную-член, когда она установлена в Lua. Его можно использовать с пользовательскими типами или просто при установке функции в sol. Ниже приведен пример, который демонстрирует, что вызов, который обычно не дает ошибок без включенных функций безопасности , вместо этого вызывает ошибки и приводит к pcallсбою оболочки безопасного вызова Lua :
2738
2739#define SOL_ALL_SAFETIES_ON 1
2740#include <sol/sol.hpp>
2741
2742#include "assert.hpp"
2743
2744int main(int, char*[]) {
2745
2746 struct protect_me {
2747 int gen(int x) {
2748 return x;
2749 }
2750 };
2751
2752 sol::state lua;
2753 lua.open_libraries(sol::lib::base);
2754 lua.new_usertype<protect_me>("protect_me",
2755 "gen", sol::protect( &protect_me::gen )
2756 );
2757
2758 lua.script(R"__(
2759 pm = protect_me.new()
2760 value = pcall(pm.gen,"wrong argument")
2761 )__");
2762 bool value = lua["value"];
2763 c_assert(!value);
2764
2765 return 0;
2766}
2767вар
2768Для подключения статических / глобальных переменных к пользовательским типам Lua
2769
2770Единственная цель этого типа тегов - работать с пользовательскими типами для предоставления my_class.my_static_var доступа, а также для предоставления доступа на основе ссылок.
2771
2772#define SOL_ALL_SAFETIES_ON 1
2773#include <sol/sol.hpp>
2774
2775#include "assert.hpp"
2776#include <iostream>
2777
2778struct test {
2779 static int number;
2780};
2781int test::number = 25;
2782
2783
2784int main() {
2785 sol::state lua;
2786 lua.open_libraries();
2787 lua.new_usertype<test>("test",
2788 "direct", sol::var(2),
2789 "number", sol::var(test::number),
2790 "ref_number", sol::var(ref(test::number))
2791 );
2792
2793 int direct_value = lua["test"]["direct"];
2794 c_assert(direct_value == 2);
2795
2796 int number = lua["test"]["number"];
2797 c_assert(number == 25);
2798 int ref_number = lua["test"]["ref_number"];
2799 c_assert(ref_number == 25);
2800
2801 test::number = 542;
2802
2803 // number is its own memory: was passed by value
2804 // So does not change
2805 int number_again = lua["test"]["number"];
2806 c_assert(number_again == 25);
2807
2808 // ref_number is just test::number
2809 // passed through ref
2810 // so, it holds a reference
2811 // which can be updated
2812 int ref_number_again = lua["test"]["ref_number"];
2813 c_assert(ref_number_again == 542);
2814 // be careful about referencing local variables,
2815 // if they go out of scope but are still reference
2816 // you'll suffer dangling reference bugs!
2817
2818 return 0;
2819}
2820« Собственность :: Содержание :: защита »
2821уступая
2822говоря функции C ++, чтобы привести ее результаты в Lua
2823
2824template <typename F>
2825yield_wrapper<F> yielding( F&& f )
2826sol::yieldingполезен для вызова функций C ++, которые должны быть преобразованы в сопрограмму Lua. Это обертка вокруг одного аргумента, который, как ожидается, будет связан как функция. Вы можете передавать его везде, где может быть связана обычная функция, за исключением определений пользовательских типов .
2827
2828сопрограмма
2829Возобновляемые / уступающие функции от Lua
2830
2831A coroutine- это ссылка на функцию в Lua, которую можно вызывать несколько раз, чтобы получить конкретный результат. Он запускается в lua_State, который использовался для его создания (см. Поток для примера того, как получить сопрограмму, которая работает в потоке, отдельном от вашего обычного «основного» lua_State ).
2832
2833Coroutine Объект полностью аналогичен protected_function объекта, с дополнительными функциями - членами , чтобы проверить , если сопрограмма дал ( call_status :: выданное ) , и, таким образом , снова работоспособной, была ли она завершена ( call_status :: ОК ) и , следовательно , не может дать больше значения, или произошла ошибка (см. коды ошибок status () и call_status ).
2834
2835Например, вы можете работать с сопрограммой следующим образом:
2836
2837co.lua
2838 function loop()
2839 while counter ~= 30
2840 do
2841 coroutine.yield(counter);
2842 counter = counter + 1;
2843 end
2844 return counter
2845 end
2846Это функция, которая дает:
2847
2848main.cpp
2849sol::state lua;
2850lua.open_libraries(sol::lib::base, sol::lib::coroutine);
2851lua.script_file("co.lua");
2852sol::coroutine cr = lua["loop"];
2853
2854for (int counter = 0; // start from 0
2855 counter < 10 && cr; // we want 10 values, and we only want to run if the coroutine "cr" is valid
2856 // Alternative: counter < 10 && cr.valid()
2857 ++counter) {
2858 // Call the coroutine, does the computation and then suspends
2859 int value = cr();
2860}
2861
2862
2863Обратите внимание, что этот код не проверяет наличие ошибок: для этого вы можете вызвать функцию и назначить ее как , а затем проверить, как в случае с protected_function . Наконец, вы можете запустить эту сопрограмму в другом потоке, выполнив следующие действия:auto result = cr();result.valid()
2864
2865main_with_thread.cpp
2866sol::state lua;
2867lua.open_libraries(sol::lib::base, sol::lib::coroutine);
2868lua.script_file("co.lua");
2869sol::thread runner = sol::thread::create(lua.lua_state());
2870sol::state_view runnerstate = runner.state();
2871sol::coroutine cr = runnerstate["loop"];
2872
2873for (int counter = 0; counter < 10 && cr; ++counter) {
2874 // Call the coroutine, does the computation and then suspends
2875 int value = cr();
2876}
2877
2878Вариант 2.
2879const char* LUA = R"(
2880 function loop()
2881 counter = 0
2882 while counter ~= 3
2883 do
2884 counter = counter + 1;
2885 coroutine.yield(counter);
2886 end
2887 return 0
2888 end
2889)";
2890
2891int main(int argc, char* argv[]) {
2892
2893 state lua; // Lua состояние.
2894 lua.open_libraries(lib::base, lib::package, sol::lib::coroutine); // открыть доп.библиотеки.
2895 lua.script(LUA);
2896// auto result = lua.safe_script(LUA, sol::script_pass_on_error);
2897 thread runner = sol::thread::create(lua.lua_state());//создает новой поток в новом состоянии.
2898 state_view runstate = runner.state();// получаем состояние для этого потока.
2899 coroutine cr = runstate["loop"];// получить типа wrap().
2900
2901 //for (int counter = 0; counter < 3; ++counter) {
2902 // int value = cr();
2903 // cout << value << endl;
2904 //};
2905 /*int p = cr.call();
2906
2907 cout << p << endl;*/
2908 while (call_status::yielded == cr.status()) {// если приостановлена, возобновить
2909 cout << " yield" << endl;
2910 int value = cr();
2911 cout << value << endl;
2912 }
2913 return 0;
2914};
2915
2916
2917
2918Ниже приведены члены sol::coroutine:
2919
2920члены
2921функция: конструктор
2922coroutine(lua_State* L, int index = -1);
2923Хватает сопрограмму по указанному индексу с учетом lua_State*.
2924
2925возвращение статуса сопрограммы
2926call_status status() const noexcept;
2927Возвращает статус сопрограммы.
2928
2929проверяет на ошибку
2930bool error() const noexcept;
2931Проверяет, произошла ли ошибка при запуске сопрограммы.
2932
2933выполняемый и явный оператор bool
2934bool runnable () const noexcept;
2935explicit operator bool() const noexcept;
2936Эти функции позволяют проверить, можно ли еще вызывать сопрограмму (имеет больше значений для выдачи и не имеет ошибок). Если у вас есть объект сопрограммы , вы можете проверить или сделать .coroutine my_co = /*...*/runnable()if ( my_co ) { /* use coroutine */ }
2937
2938вызывая сопрограмму
2939template<typename... Args>
2940protected_function_result operator()( Args&&... args );
2941
2942template<typename... Ret, typename... Args>
2943decltype(auto) call( Args&&... args );
2944
2945template<typename... Ret, typename... Args>
2946decltype(auto) operator()( types<Ret...>, Args&&... args );
2947Вызывает сопрограмму. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Затем проверьте дополнительную информацию об успешном выполнении или просто проверьте объект сопрограммы в сообщении ifs, как показано выше .my_co(sol::types<int, string>, ...)status()
2948
2949защищенная
2950Вызовы функций Lua, которые перехватывают ошибки и обеспечивают обработку ошибок
2951
2952class protected_function : public reference;
2953typedef protected_function safe_function;
2954Вдохновленный запросом starwing в старом репозитории sol , этот класс обеспечивает тот же интерфейс, что и функция, но с усиленной защитой и потенциальным обработчиком ошибок для любых ошибок Lua и исключений C ++. Вы можете получить функцию непосредственно из стека, используя конструктор, или передать ей две допустимые функции, которые мы продемонстрируем чуть позже.
2955
2956При вызове без указания типов возврата, указанных sol::types<...>списком или списком типов шаблонов, он генерирует класс protected_function_result, который неявно преобразуется в запрошенный тип возврата. Например:call<Ret...>( ... )
2957
2958 function got_problems( error_msg )
2959 return "got_problems handler: " .. error_msg
2960 end
2961
2962 function woof ( bark_energy )
2963 if bark_energy < 20 then
2964 error("*whine*")
2965 end
2966 return (bark_energy * (bark_power / 4))
2967 end
2968
2969 function woofers ( bark_energy )
2970 if bark_energy < 10 then
2971 error("*whine*")
2972 end
2973 return (bark_energy * (bark_power / 4))
2974 end
2975 )";
2976Следующий код C ++ будет вызывать эту функцию из этого файла и извлекать возвращаемое значение, если только не происходит ошибка, в этом случае вы можете связать функцию обработки ошибок следующим образом:
2977
2978#define SOL_ALL_SAFETIES_ON 1
2979#include <sol/sol.hpp>
2980
2981#include <iostream>
2982
2983int main () {
2984 sol::state lua;
2985 lua.open_libraries(sol::lib::base);
2986
2987 lua.script(code);
2988
2989 sol::protected_function problematic_woof = lua["woof"];
2990 problematic_woof.error_handler = lua["got_problems"];
2991
2992 auto firstwoof = problematic_woof(20);
2993 if ( firstwoof.valid() ) {
2994 // Can work with contents
2995 double numwoof = firstwoof;
2996 cout << "Got value: " << numwoof << endl;
2997 }
2998 else{
2999 // An error has occured
3000 sol::error err = firstwoof;
3001 string what = err.what();
3002 cout << what << endl;
3003 }
3004
3005 // errors, calls handler and then returns a string error from Lua at the top of the stack
3006 auto secondwoof = problematic_woof(19);
3007 if (secondwoof.valid()) {
3008 // Call succeeded
3009 double numwoof = secondwoof;
3010 cout << "Got value: " << numwoof << endl;
3011 }
3012 else {
3013 // Call failed
3014 // Note that if the handler was successfully called, this will include
3015 // the additional appended error message information of
3016 // "got_problems handler: " ...
3017 sol::error err = secondwoof;
3018 string what = err.what();
3019 cout << what << endl;
3020 }
3021Этот код намного длиннее, чем его аналог функции, но позволяет человеку проверять наличие ошибок. Тип здесь для autoявляются sol::protected_function_result. Они неявно преобразуются в типы результатов, как и все типы в стиле прокси .
3022
3023В качестве альтернативы, при плохом или хорошем вызове функции, вы можете использовать, sol::optionalчтобы проверить, успешен ли вызов или нет:
3024
3025 // can also use optional to tell things
3026 sol::optional<double> maybevalue = problematic_woof(19);
3027 if (maybevalue) {
3028 // Have a value, use it
3029 double numwoof = maybevalue.value();
3030 cout << "Got value: " << numwoof << endl;
3031 }
3032 else {
3033 cout << "No value!" << endl;
3034 }
3035
3036 cout << endl;
3037
3038 return 0;
3039}
3040Это делает код немного более кратким и легким для размышления, если вы не хотите беспокоиться о прочтении ошибки. К счастью, в отличие от этого sol::unsafe_function_result, вы можете сохранять sol::protected_function_resultпеременные и помещать / помещать вещи над ней в стек, где находятся возвращаемые значения. Это делает его немного более гибким, чем жесткий, производительный sol::unsafe_function_resultтип, который получается при вызове sol :: unsafe_function .
3041
3042Если вы уверены, что результат был успешным, вы также можете просто указать нужный вам тип (например, doubleили string), и он получит его. Но, если это не сработает, sol может бросить и / или запаниковать, если у вас включены функции безопасности :
3043
3044
3045// construct with function + error handler
3046// shorter than old syntax
3047sol::protected_function problematicwoof(lua["woof"], lua["got_problems"]);
3048
3049// dangerous if things go wrong!
3050double value = problematicwoof(19);
3051Наконец, важно отметить, что вы можете установить обработчик по умолчанию. Функция описана ниже: пожалуйста, используйте ее, чтобы избежать необходимости постоянно устанавливать обработчики ошибок:
3052
3053// sets got_problems as the default
3054// handler for all protected_function errors
3055sol::protected_function::set_default_handler(lua["got_problems"]);
3056
3057sol::protected_function problematicwoof = lua["woof"];
3058sol::protected_function problematicwoofers = lua["woofers"];
3059
3060double value = problematicwoof(19);
3061double value2 = problematicwoof(9);
3062члены
3063конструктор: protected_function
3064template <typename T>
3065protected_function( T&& func, reference handler = sol::protected_function::get_default_handler() );
3066protected_function( lua_State* L, int index = -1, reference handler = sol::protected_function::get_default_handler() );
3067Создаёт protected_function. Используйте версию с двумя аргументами, чтобы легче передавать пользовательскую функцию обработки ошибок. Вы также можете установить переменную-член error_handler после создания позже. protected_functionвсегда будет использовать последний обработчик ошибок, установленный для переменной, который является либо тем, что вы передали ей, либо значением по умолчанию во время создания .
3068
3069функция: вызов оператора / вызов защищенной функции
3070template<typename... Args>
3071protected_function_result operator()( Args&&... args );
3072
3073template<typename... Ret, typename... Args>
3074decltype(auto) call( Args&&... args );
3075
3076template<typename... Ret, typename... Args>
3077decltype(auto) operator()( types<Ret...>, Args&&... args );
3078Вызывает функцию. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Если вы не указали тип возвращаемого значения каким-либо образом, он выдаст s .my_func(sol::types<int, string>, ...)protected_function_result
3079
3080Заметка
3081
3082Все аргументы переданы. В отличие от get / set / operator [] для sol :: state или sol :: table , семантика значений здесь не используется. Это пересылка эталонной семантики, которая не копирует / не перемещает, если это не сделано специально для принимающих функций / специально для пользователя.
3083
3084обработчики по умолчанию
3085static const reference& get_default_handler ();
3086static void set_default_handler( reference& ref );
3087Получите и установите объект Lua, который используется в качестве обработчика ошибок по умолчанию. По умолчанию используется обработчик ошибок no-ref. Вы можете изменить это, позвонив или подобный: все, что производит ссылку, должно быть хорошо.protected_function::set_default_handler( lua["my_handler"] );
3088
3089переменная: обработчик
3090reference error_handler;
3091Обработчик ошибок, который вызывается, если возникает ошибка времени выполнения, которую может обнаружить Lua. Функция обработчика ошибок должна принимать один строковый аргумент (используйте тип std :: string, если вы хотите использовать функцию C ++, связанную с lua в качестве обработчика ошибок) и возвращать единственный строковый аргумент (опять же, возвращать std :: string или строковый аргумент из функции C ++, если вы используете его в качестве обработчика ошибок). Если исключения включены, sol попытается преобразовать .what()аргумент исключения в строку, а затем вызовет функцию обработки ошибок. Это ссылка , так как она должна ссылаться на то, что существует в реестре lua или в стеке Lua. При создании автоматически устанавливается обработчик ошибок по умолчанию protected_function.
3092
3093Заметка
3094
3095protected_function_resultбезопасно вызывает его значения из стека при вызове его деструктора, отслеживая индекс и количество аргументов, которые должны были быть возвращены. lua_removeНапример, если вы удалите элементы, расположенные ниже, с помощью него, он будет работать не так, как ожидалось. Пожалуйста, не выполняйте фундаментальные операции по перестановке стека, пока не будет вызван деструктор (толкание / выталкивание над ним просто отлично).
3096
3097Чтобы узнать больше о том, как обрабатываются аргументы функции, см. Это примечание .
3098
3099функция
3100вызов функций, связанных с Lua
3101
3102Заметка
3103
3104Эта абстракция предполагает, что функция работает безопасно. Если вы ожидаете, что в вашем коде есть ошибки (например, вы не всегда имеете явный контроль над ним или пытаетесь отлаживать ошибки), пожалуйста, явно используйте sol :: protected_function . Вы также можете сделать по sol::functionумолчанию sol::protected_function, включив функции безопасности .
3105
3106class unsafe_function : public reference;
3107typedef unsafe_function function;
3108Функция является верной версией защищенной функции , исключающей необходимость проверок типов и обработки ошибок (таким образом, в некоторых случаях незначительно увеличивает скорость). Это тип функции по умолчанию sol. Возьмите функцию прямо из стека, используя конструктор:
3109
3110конструктор: unsafe_function
3111unsafe_function(lua_State* L, int index = -1);
3112Вызывает конструктор и создает этот тип прямо из стека. Например:
3113
3114funcs.lua
3115
3116 bark_power = 11;
3117
3118 function woof ( bark_energy )
3119 return (bark_energy * (bark_power / 4))
3120 end
3121Следующий код C ++ вызовет эту функцию из этого файла и получит возвращаемое значение:
3122
3123#define SOL_ALL_SAFETIES_ON 1
3124#include <sol/sol.hpp>
3125
3126#include "assert.hpp"
3127
3128int main (int, char*[]) {
3129
3130 sol::state lua;
3131
3132 lua.script(code);
3133
3134 sol::function woof = lua["woof"];
3135 double numwoof = woof(20);
3136 c_assert(numwoof == 55.0);
3137Вызов woof(20)генерирует unsafe_function_result , который затем неявно преобразуется в doubleпосле вызова . Промежуточный временный function_resultобъект затем разрушается, выводя результаты вызова функции Lua из стека Lua.
3138
3139Вы также можете вернуть несколько значений с помощью tupleили, если вам нужно привязать их к существующим переменным, используйте sol::tie:
3140
3141
3142 lua.script( "function f () return 10, 11, 12 end" );
3143
3144 sol::function f = lua["f"];
3145 tuple<int, int, int> abc = f();
3146 c_assert(get<0>(abc) == 10);
3147 c_assert(get<1>(abc) == 11);
3148 c_assert(get<2>(abc) == 12);
3149 // or
3150 int a, b, c;
3151 sol::tie(a, b, c) = f();
3152 c_assert(a == 10);
3153 c_assert(b == 11);
3154 c_assert(c == 12);
3155
3156 return 0;
3157}
3158Это значительно облегчает работу с несколькими возвращаемыми значениями. Использование tieиз стандарта C ++ приведет к висящим ссылкам или плохому поведению из-за очень плохого способа, которым кортежи / C ++ tieбыли определены и реализованы: используйте вместо этого, чтобы удовлетворить любые требования множественного возврата.sol::tie( ... )
3159
3160Предупреждение
3161
3162НЕ сохраняйте возвращаемый тип unsafe_function_result ( function_resultкогда настройки безопасности не включены ) с помощью auto, как в , и НЕ храните его где-либо. В отличие от его аналога protected_function_result , хранить его НЕ безопасно, так как предполагается, что его возвращаемые типы все еще находятся на вершине стека, а при вызове деструктора выскакивает число результатов, которые функция должна была вернуть с вершины стека. Если вы возитесь со стеком Lua между сохранением и его уничтожением, вы будете подвержены невероятному количеству удивительных и трудно отслеживаемых ошибок. Не делай этого.auto numwoof = woof(20);function_resultfunction_result
3163
3164функция: оператор вызова / вызов функции
3165template<typename... Args>
3166unsafe_function_result operator()( Args&&... args );
3167
3168template<typename... Ret, typename... Args>
3169decltype(auto) call( Args&&... args );
3170
3171template<typename... Ret, typename... Args>
3172decltype(auto) operator()( types<Ret...>, Args&&... args );
3173Вызывает функцию. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Функция предполагает, что ошибок времени выполнения нет, и, таким образом, будет вызывать функцию, если обнаружится ошибка, и в противном случае может вернуть мусорные / поддельные значения, если пользователь не будет осторожен.my_func(sol::types<int, string>, ...)atpanic
3174
3175Чтобы узнать больше о том, как обрабатываются аргументы функции, см. Это примечание
3176
3177« Tie :: Contents :: protected_function »
3178
3179защищенная
3180Вызовы функций Lua, которые перехватывают ошибки и обеспечивают обработку ошибок
3181
3182class protected_function : public reference;
3183typedef protected_function safe_function;
3184Вдохновленный запросом starwing в старом репозитории sol , этот класс обеспечивает тот же интерфейс, что и функция, но с усиленной защитой и потенциальным обработчиком ошибок для любых ошибок Lua и исключений C ++. Вы можете получить функцию непосредственно из стека, используя конструктор, или передать ей две допустимые функции, которые мы продемонстрируем чуть позже.
3185
3186При вызове без указания типов возврата, указанных sol::types<...>списком или списком типов шаблонов, он генерирует класс protected_function_result, который неявно преобразуется в запрошенный тип возврата. Например:call<Ret...>( ... )
3187
3188
3189 function got_problems( error_msg )
3190 return "got_problems handler: " .. error_msg
3191 end
3192
3193 function woof ( bark_energy )
3194 if bark_energy < 20 then
3195 error("*whine*")
3196 end
3197 return (bark_energy * (bark_power / 4))
3198 end
3199
3200 function woofers ( bark_energy )
3201 if bark_energy < 10 then
3202 error("*whine*")
3203 end
3204 return (bark_energy * (bark_power / 4))
3205 end
3206 )";
3207Следующий код C ++ будет вызывать эту функцию из этого файла и извлекать возвращаемое значение, если только не происходит ошибка, в этом случае вы можете связать функцию обработки ошибок следующим образом:
3208
3209
3210#define SOL_ALL_SAFETIES_ON 1
3211#include <sol/sol.hpp>
3212
3213#include <iostream>
3214
3215int main () {
3216 sol::state lua;
3217 lua.open_libraries(sol::lib::base);
3218
3219 lua.script(code);
3220
3221 sol::protected_function problematic_woof = lua["woof"];
3222 problematic_woof.error_handler = lua["got_problems"];
3223
3224 auto firstwoof = problematic_woof(20);
3225 if ( firstwoof.valid() ) {
3226 // Can work with contents
3227 double numwoof = firstwoof;
3228 cout << "Got value: " << numwoof << endl;
3229 }
3230 else{
3231 // An error has occured
3232 sol::error err = firstwoof;
3233 string what = err.what();
3234 cout << what << endl;
3235 }
3236
3237 // errors, calls handler and then returns a string error from Lua at the top of the stack
3238 auto secondwoof = problematic_woof(19);
3239 if (secondwoof.valid()) {
3240 // Call succeeded
3241 double numwoof = secondwoof;
3242 cout << "Got value: " << numwoof << endl;
3243 }
3244 else {
3245 // Call failed
3246 // Note that if the handler was successfully called, this will include
3247 // the additional appended error message information of
3248 // "got_problems handler: " ...
3249 sol::error err = secondwoof;
3250 string what = err.what();
3251 cout << what << endl;
3252 }
3253Этот код намного длиннее, чем его аналог функции, но позволяет человеку проверять наличие ошибок. Тип здесь для autoявляются sol::protected_function_result. Они неявно преобразуются в типы результатов, как и все типы в стиле прокси .
3254
3255В качестве альтернативы, при плохом или хорошем вызове функции, вы можете использовать, sol::optionalчтобы проверить, успешен ли вызов или нет:
3256
3257 // can also use optional to tell things
3258 sol::optional<double> maybevalue = problematic_woof(19);
3259 if (maybevalue) {
3260 // Have a value, use it
3261 double numwoof = maybevalue.value();
3262 cout << "Got value: " << numwoof << endl;
3263 }
3264 else {
3265 cout << "No value!" << endl;
3266 }
3267
3268 cout << endl;
3269
3270 return 0;
3271}
3272Это делает код немного более кратким и легким для размышления, если вы не хотите беспокоиться о прочтении ошибки. К счастью, в отличие от этого sol::unsafe_function_result, вы можете сохранять sol::protected_function_resultпеременные и помещать / помещать вещи над ней в стек, где находятся возвращаемые значения. Это делает его немного более гибким, чем жесткий, производительный sol::unsafe_function_resultтип, который получается при вызове sol :: unsafe_function .
3273
3274Если вы уверены, что результат был успешным, вы также можете просто указать нужный вам тип (например, doubleили string), и он получит его. Но, если это не сработает, sol может бросить и / или запаниковать, если у вас включены функции безопасности :
3275
3276// construct with function + error handler
3277// shorter than old syntax
3278sol::protected_function problematicwoof(lua["woof"], lua["got_problems"]);
3279
3280// dangerous if things go wrong!
3281double value = problematicwoof(19);
3282Наконец, важно отметить, что вы можете установить обработчик по умолчанию. Функция описана ниже: пожалуйста, используйте ее, чтобы избежать необходимости постоянно устанавливать обработчики ошибок:
3283
3284// sets got_problems as the default
3285// handler for all protected_function errors
3286sol::protected_function::set_default_handler(lua["got_problems"]);
3287
3288sol::protected_function problematicwoof = lua["woof"];
3289sol::protected_function problematicwoofers = lua["woofers"];
3290
3291double value = problematicwoof(19);
3292double value2 = problematicwoof(9);
3293члены
3294конструктор: protected_function
3295template <typename T>
3296protected_function( T&& func, reference handler = sol::protected_function::get_default_handler() );
3297protected_function( lua_State* L, int index = -1, reference handler = sol::protected_function::get_default_handler() );
3298Создаёт protected_function. Используйте версию с двумя аргументами, чтобы легче передавать пользовательскую функцию обработки ошибок. Вы также можете установить переменную-член error_handler после создания позже. protected_functionвсегда будет использовать последний обработчик ошибок, установленный для переменной, который является либо тем, что вы передали ей, либо значением по умолчанию во время создания .
3299
3300функция: вызов оператора / вызов защищенной функции
3301template<typename... Args>
3302protected_function_result operator()( Args&&... args );
3303
3304template<typename... Ret, typename... Args>
3305decltype(auto) call( Args&&... args );
3306
3307template<typename... Ret, typename... Args>
3308decltype(auto) operator()( types<Ret...>, Args&&... args );
3309Вызывает функцию. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Если вы не указали тип возвращаемого значения каким-либо образом, он выдаст s .my_func(sol::types<int, string>, ...)protected_function_result
3310
3311Заметка
3312
3313Все аргументы переданы. В отличие от get / set / operator [] для sol :: state или sol :: table , семантика значений здесь не используется. Это пересылка эталонной семантики, которая не копирует / не перемещает, если это не сделано специально для принимающих функций / специально для пользователя.
3314
3315обработчики по умолчанию
3316static const reference& get_default_handler ();
3317static void set_default_handler( reference& ref );
3318Получите и установите объект Lua, который используется в качестве обработчика ошибок по умолчанию. По умолчанию используется обработчик ошибок no-ref. Вы можете изменить это, позвонив или подобный: все, что производит ссылку, должно быть хорошо.protected_function::set_default_handler( lua["my_handler"] );
3319
3320переменная: обработчик
3321reference error_handler;
3322Обработчик ошибок, который вызывается, если возникает ошибка времени выполнения, которую может обнаружить Lua. Функция обработчика ошибок должна принимать один строковый аргумент (используйте тип std :: string, если вы хотите использовать функцию C ++, связанную с lua в качестве обработчика ошибок) и возвращать единственный строковый аргумент (опять же, возвращать std :: string или строковый аргумент из функции C ++, если вы используете его в качестве обработчика ошибок). Если исключения включены, sol попытается преобразовать .what()аргумент исключения в строку, а затем вызовет функцию обработки ошибок. Это ссылка , так как она должна ссылаться на то, что существует в реестре lua или в стеке Lua. При создании автоматически устанавливается обработчик ошибок по умолчанию protected_function.
3323
3324Заметка
3325
3326protected_function_resultбезопасно вызывает его значения из стека при вызове его деструктора, отслеживая индекс и количество аргументов, которые должны были быть возвращены. lua_removeНапример, если вы удалите элементы, расположенные ниже, с помощью него, он будет работать не так, как ожидалось. Пожалуйста, не выполняйте фундаментальные операции по перестановке стека, пока не будет вызван деструктор (толкание / выталкивание над ним просто отлично).
3327
3328Чтобы узнать больше о том, как обрабатываются аргументы функции, см. Это примечание .
3329
3330proxy, (protectedunsafe) _function_result - производные proxy_base
3331`` table [x] `` и `` function (…) `` структура преобразования
3332
3333template <typename Recurring>
3334struct proxy_base;
3335
3336template <typename Table, typename Key>
3337struct proxy : proxy_base<...>;
3338
3339struct stack_proxy: proxy_base<...>;
3340
3341struct unsafe_function_result : proxy_base<...>;
3342
3343struct protected_function_result: proxy_base<...>;
3344Эти классы предоставляют оператор неявного присваивания operator=(for set) и оператор неявного преобразования (for ) для поддержки элементов, извлеченных из базовой реализации Lua, в частности sol :: table и результатов вызовов функций для sol :: function и sol :: protected_function .operator Tget
3345
3346прокси
3347proxyвозвращается поисками в sol :: table и табличные сущности. Поскольку он основан на ключе и типе таблицы, его было бы сложно записать по буквам: вы можете захватить его, используя слово, autoесли вам кажется, что вам нужно нести его по какой-то причине перед его использованием. proxyлениво оценивает свои аргументы, когда вы наконец звоните getили setпо нему. Вот несколько примеров с использованием следующего скрипта lua:
3348
3349 bark = {
3350 woof = {
3351 [2] = "arf!"
3352 }
3353 }
3354После загрузки этого файла или помещения его в строку и чтения строки непосредственно в lua (см. Состояние ), вы можете начать разбираться с ним в C ++ примерно так:
3355
3356#define SOL_ALL_SAFETIES_ON 1
3357#include <sol/sol.hpp>
3358
3359#include "assert.hpp"
3360
3361#include <iostream>
3362
3363int main () {
3364 sol::state lua;
3365 lua.open_libraries(sol::lib::base);
3366 lua.script(code);
3367
3368 // produces proxy, implicitly converts to string, quietly destroys proxy
3369 string arf_string = lua["bark"]["woof"][2];
3370
3371 // lazy-evaluation of tables
3372 auto x = lua["bark"];
3373 auto y = x["woof"];
3374 auto z = y[2];
3375
3376 // retrivies value inside of lua table above
3377 string value = z;
3378 c_assert(value == "arf!");
3379
3380 // Can change the value later...
3381 z = 20;
3382
3383 // Yay, lazy-evaluation!
3384 int changed_value = z; // now it's 20!
3385 c_assert(changed_value == 20);
3386 lua.script("assert(bark.woof[2] == 20)");
3387Мы не рекомендуем использовать proxyленивое вычисление выше для использования между классами или между функциями: это больше, чем вы можете сделать, чтобы сохранить ссылку на значение, которое вам нравится, вызвать скрипт или запустить функцию lua, а затем получить его впоследствии , Вы также можете установить функции (и функциональные объекты) таким образом, а также получить их:
3388 lua["a_new_value"] = 24;
3389 lua["chase_tail"] = [](int chasing) {
3390 int r = 2;
3391 for (int i = 0; i < chasing; ++i) {
3392 r *= r;
3393 }
3394 return r;
3395 };
3396
3397 lua.script("assert(a_new_value == 24)");
3398 lua.script("assert(chase_tail(2) == 16)");
3399
3400 return 0;
3401}
3402члены
3403функции: [перегружено] неявное преобразование get
3404requires( sol::is_primitive_type<T>::value == true )
3405template <typename T>
3406operator T() const;
3407
3408requires( sol::is_primitive_type<T>::value == false )
3409template <typename T>
3410operator T&() const;
3411Получает значение, связанное с ключами, сгенерированными прокси, и передает его типу T. Обратите внимание, что эта функция всегда будет возвращать T&неконстантную ссылку на типы, которые не основаны на sol :: reference и не являются примитивным типом lua.
3412
3413функция: получить значение
3414template <typename T>
3415decltype(auto) get( ) const;
3416Получает значение, связанное с ключами, и преобразует его в тип T.
3417
3418функция: опционально получить значение
3419template <typename T, typename Otherwise>
3420optional<T> get_or( Otherwise&& otherise ) const;
3421Получает значение, связанное с ключами, и преобразует его в тип T. Если это не правильный тип, он возвратит sol::nulloptвместо.
3422
3423функция: [перегружено] опционально получить или создать значение
3424template <typename T>
3425decltype(auto) get_or_create();
3426template <typename T, typename Otherwise>
3427decltype(auto) get_or_create( Otherwise&& other );
3428Получает значение, связанное с ключами, если оно существует. Если это не так, он установит его со значением и вернет результат.
3429
3430operator[]прокси-только члены
3431функция: действует
3432bool valid () const;
3433Возвращает, действительно ли этот прокси ссылается на действительный объект. Он использует sol :: stack :: probe_get_field, чтобы определить, действительно ли он действителен.
3434
3435функции: [перегружено] неявное множество
3436requires( sol::detail::Function<Fx> == false )
3437template <typename T>
3438proxy& operator=( T&& value );
3439
3440requires( sol::detail::Function<Fx> == true )
3441template <typename Fx>
3442proxy& operator=( Fx&& function );
3443Устанавливает значение, связанное с ключами, с которыми был сгенерирован прокси value. Если это функция, звонки set_function. Если это не так, просто звонки set. Не существует в unsage_function_result или protected_function_result .
3444
3445Функция: установить вызываемый
3446template <typename Fx>
3447proxy& set_function( Fx&& fx );
3448Устанавливает значение, связанное с ключами, с которыми был создан прокси, для функции fx. Не существует в unsafe_function_result или protected_function_result .
3449
3450функция: установить значение
3451template <typename T>
3452proxy& set( T&& value );
3453Устанавливает значение, связанное с ключами, с которыми был сгенерирован прокси value. Не существует в unsafe_function_result или protected_function_result .
3454
3455stack_proxy
3456sol::stack_proxyэто то, что возвращается sol :: variadic_args и другими частями фреймворка. Он похож на прокси, но предназначен для псевдонима стекового индекса, а не именованной переменной.
3457
3458unsafe_function_result
3459unsafe_function_resultявляется неявным рабочим преобразования только для промежуточного и только промежуточного времени, когда вызывается функция . Он НЕ предназначен для хранения или захвата auto. Это обеспечивает быстрый доступ к нужному базовому значению. Он не реализует set/ set_function/ templated operator=, так как присутствует на прокси .
3460
3461Этот тип, однако, разрешает доступ к нескольким базовым значениям. Используется result.get<Type>(index_offset)для получения объекта со Typeсмещением index_offsetв результатах. Смещение 0 основано. Не указав аргумент, по умолчанию значение равно 0.
3462
3463unsafe_function_resultтакже есть begin()и end()функции, которые возвращают (почти) случайные итераторы. Они возвращают тип прокси, который может быть неявно преобразован в stack_proxy .
3464
3465protected_function_result
3466protected_function_resultэто более хорошая версия, unsafe_function_resultкоторая может быть использована для обнаружения ошибок. Это дает безопасный доступ к желаемой базовой стоимости. Он не реализует set// set_functionшаблон, operator=как присутствует на прокси .
3467
3468Этот тип, однако, разрешает доступ к нескольким базовым значениям. Используется result.get<Type>(index_offset)для получения объекта со Typeсмещением index_offsetв результатах. Смещение 0 основано. Не указав аргумент, по умолчанию значение равно 0.
3469
3470unsafe_function_resultтакже есть begin()и end()функции, которые возвращают (почти) случайные итераторы. Они возвращают тип прокси, который может быть неявно преобразован в stack_proxy .
3471
3472на функциональные объекты и прокси
3473Заметка
3474
3475Начиная с последних версий sol3 (2.18.2 и выше), это больше не проблема, поскольку даже связанные классы будут иметь любой обнаруживаемый оператор вызова функции, автоматически связанный с объектом, чтобы позволить этому работать без необходимости использовать .setили .set_function. Примечание здесь сохранено для потомков и информации для более старых версий. Есть только несколько небольших предостережений, см. Эту заметку здесь .
3476
3477« This_environment :: Contents :: as_container »
3478
3479variadic_args
3480прозрачный аргумент для работы с несколькими параметрами функции
3481
3482struct variadic_args;
3483Этот класс предназначен для представления каждого отдельного аргумента в его текущем индексе и за его пределами в списке функций. Он не увеличивает количество аргументов и поэтому прозрачен. Вы можете разместить его в любом месте списка аргументов, и он будет представлять все объекты в вызове функции, которые идут после него, независимо от того, перечислены они явно или нет.
3484
3485variadic_argsтакже есть begin()и end()функции, которые возвращают (почти) итераторы со случайным доступом. Они возвращают тип прокси, который может быть неявно преобразован в тип, который вы хотите, очень похожий на тип прокси таблицы .
3486
3487
3488#define SOL_ALL_SAFETIES_ON 1
3489#include <sol/sol.hpp>
3490
3491#include <iostream>
3492
3493int main() {
3494 cout << "=== variadic_args ===" << endl;
3495
3496 sol::state lua;
3497 lua.open_libraries(sol::lib::base);
3498
3499 // Function requires 2 arguments
3500 // rest can be variadic, but:
3501 // va will include everything after "a" argument,
3502 // which means "b" will be part of the varaidic_args list too
3503 // at position 0
3504 lua.set_function("v", [](int a, sol::variadic_args va, int /*b*/) {
3505 int r = 0;
3506 for (auto v : va) {
3507 int value = v; // get argument out (implicit conversion)
3508 // can also do int v = v.as<int>();
3509 // can also do int v = va.get<int>(i); with index i
3510 r += value;
3511 }
3512 // Only have to add a, b was included from variadic_args and beyond
3513 return r + a;
3514 });
3515
3516 lua.script("x = v(25, 25)");
3517 lua.script("x2 = v(25, 25, 100, 50, 250, 150)");
3518 lua.script("x3 = v(1, 2, 3, 4, 5, 6)");
3519 // will error: not enough arguments
3520 //lua.script("x4 = v(1)");
3521
3522 lua.script("assert(x == 50)");
3523 lua.script("assert(x2 == 600)");
3524 lua.script("assert(x3 == 21)");
3525 lua.script("print(x)"); // 50
3526 lua.script("print(x2)"); // 600
3527 lua.script("print(x3)"); // 21
3528
3529 cout << endl;
3530
3531 return 0;
3532}
3533Вы также можете «сохранить» аргументы и т.п. позже, вставив их в vector<sol::object>или что-то подобное, что сериализует их в реестр. Ниже приведен пример сохранения всех аргументов, предоставленных sol::variadic_argsв лямбда-переменной захвата с именем args.
3534
3535#define SOL_ALL_SAFETIES_ON 1
3536#include <sol/sol.hpp>
3537
3538#include <iostream>
3539#include <functional>
3540
3541int main() {
3542
3543 cout << "=== variadic_args serialization/storage ===" << endl;
3544
3545 sol::state lua;
3546 lua.open_libraries(sol::lib::base);
3547
3548 function<void()> function_storage;
3549
3550 auto store_routine = [&function_storage] (sol::function f, sol::variadic_args va) {
3551 function_storage = [f, args = vector<sol::object>(va.begin(), va.end())]() {
3552 f(sol::as_args(args));
3553 };
3554 };
3555
3556 lua.set_function("store_routine", store_routine);
3557
3558 lua.script(R"(
3559function a(name)
3560 print(name)
3561end
3562store_routine(a, "some name")
3563)");
3564 function_storage();
3565
3566 lua.script(R"(
3567function b(number, text)
3568 print(number, "of", text)
3569end
3570store_routine(b, 20, "these apples")
3571)");
3572 function_storage();
3573
3574 cout << endl;
3575
3576 return 0;
3577}
3578Наконец, обратите внимание, что вы можете использовать sol::variadic_argsконструктор для «смещения» / «смещения» просматриваемых аргументов:
3579
3580
3581#define SOL_ALL_SAFETIES_ON 1
3582#include <sol/sol.hpp>
3583
3584#include <iostream>
3585
3586int main () {
3587
3588 cout << "=== variadic_args shifting constructor ===" << endl;
3589
3590 sol::state lua;
3591 lua.open_libraries(sol::lib::base);
3592
3593 lua.set_function("f", [](sol::variadic_args va) {
3594 int r = 0;
3595 sol::variadic_args shifted_va(va.lua_state(), 3);
3596 for (auto v : shifted_va) {
3597 int value = v;
3598 r += value;
3599 }
3600 return r;
3601 });
3602
3603 lua.script("x = f(1, 2, 3, 4)");
3604 lua.script("x2 = f(8, 200, 3, 4)");
3605 lua.script("x3 = f(1, 2, 3, 4, 5, 6)");
3606
3607 lua.script("print(x)"); // 7
3608 lua.script("print(x2)"); // 7
3609 lua.script("print(x3)"); // 18
3610
3611 cout << endl;
3612
3613 return 0;
3614}
3615« Необязательный <T> :: Contents :: variadic_results »
3616
3617перегрузка
3618вызов различных функций в зависимости от номера / типа аргумента
3619
3620функция: создать перегруженный набор
36211
36222
36233
36244
36255
3626template <typename... Args>
3627struct overloaded_set : tuple<Args...> { /* ... */ };
3628
3629template <typename... Args>
3630overloaded_set<Args...> overload( Args&&... args );
3631Фактически созданный класс по sol::overloadсути является оберткой типов, tupleкоторая сообщает библиотеке, что создается перегрузка. Функция помогает пользователям создавать перегруженные функции, которые можно вызывать из Lua, используя 1 имя, но несколько аргументов. Он предназначен для замены спагетти кода, где пользователи макетируют это, делая странные операторы if и переключая, какую версию функции вызывать на основе luaL_check {number / udata / string} .
3632
3633Заметка
3634
3635Обратите внимание, что параметры по умолчанию в функции (например, ) не существуют вне забавы C ++ во время компиляции. Когда эта функция связывается или сериализуется в инфраструктуру Lua, она связывается как функция, принимающая 1 аргумент, а не 2 функции, принимающие либо 0, либо 1 аргумент. Если вы хотите добиться того же эффекта, вам нужно использовать перегрузку и явно вызывать ту версию функции, которую вы хотите. В C ++ нет магии, которая позволяла бы мне получать параметры по умолчанию и устанавливать их автоматически.int func(int a = 20)
3636
3637Заметка
3638
3639Разрешение перегрузки может зависеть от настроек конфигурации на страницах безопасности . Например, невозможно отличить целые числа (uint8_t, in32_t и т. Д.) От типов с плавающей запятой (float, double, half), когда они SOL_SAFE_NUMERICSне включены.
3640
3641Его использование простое: везде, где вы можете передать тип функции в Lua, будь то пользовательский тип или вы просто устанавливаете какую-либо функцию с помощью setили set_function(для таблицы или состояния (_view) ), просто оберните функции, которые вы хотите Рассмотрим разрешение перегрузки для одной функции следующим образом:
3642
3643sol::overload( func1, func2, ... funcN );
3644Функции могут быть любым видом функции / функционального объекта (лямбда). Учитывая эти функции и структуру:
3645
3646#define SOL_ALL_SAFETIES_ON 1
3647#include <sol/sol.hpp>
3648
3649#include "assert.hpp"
3650
3651#include <iostream>
3652
3653struct pup {
3654 int barks = 0;
3655
3656 void bark () {
3657 ++barks; // bark!
3658 }
3659
3660 bool is_cute () const {
3661 return true;
3662 }
3663};
3664
3665void ultra_bark( pup& p, int barks) {
3666 for (; barks --> 0;) p.bark();
3667}
3668
3669void picky_bark( pup& p, string s) {
3670 if ( s == "bark" )
3671 p.bark();
3672}
3673Затем вы используете его так же, как и для любой другой части API:
3674
3675
3676int main () {
3677 cout << "=== overloading with members ===" << endl;
3678
3679 sol::state lua;
3680 lua.open_libraries(sol::lib::base);
3681
3682 lua.set_function( "bark", sol::overload(
3683 ultra_bark,
3684 []() { return "the bark from nowhere"; }
3685 ) );
3686
3687 lua.new_usertype<pup>( "pup",
3688 // regular function
3689 "is_cute", &pup::is_cute,
3690 // overloaded function
3691 "bark", sol::overload( &pup::bark, &picky_bark )
3692 );
3693Выполнение следующих действий в Lua вызовет определенные выбранные перегрузки и связанные с ними функции:
3694
3695 1
3696 2
3697 3
3698 4
3699 5
3700 6
3701 7
3702 8
3703 9
370410
370511
370612
370713
370814
370915
371016
371117
371218
371319
371420
3715 const auto& code = R"(
3716 barker = pup.new()
3717 print(barker:is_cute())
3718 barker:bark() -- calls member function pup::bark
3719 barker:bark("meow") -- picky_bark, no bark
3720 barker:bark("bark") -- picky_bark, bark
3721
3722 bark(barker, 20) -- calls ultra_bark
3723 print(bark()) -- calls lambda which returns that string
3724 )";
3725
3726 lua.script(code);
3727
3728 pup& barker = lua["barker"];
3729 cout << barker.barks << endl;
3730 c_assert(barker.barks == 22);
3731
3732 cout << endl;
3733 return 0;
3734}
3735Заметка
3736
3737Перегрузка выполняется в системе «первым пришел - первым обслужен». Это означает, что если две перегрузки являются совместимыми, работоспособными перегрузками, он выберет первую в списке.
3738
3739Обратите внимание, что из-за этой системы вы можете использовать sol :: variadic_args, чтобы сделать функцию, которая служит «запасным вариантом». Убедитесь, что это последняя указанная функция в списке функций для . Этот пример показывает, как .sol::overload( ... )
3740
3741Заметка
3742
3743Пожалуйста, имейте в виду, что выполнение этого требует затрат времени выполнения, чтобы найти правильную перегрузку. Стоимость напрямую зависит не от количества перегрузок, а от количества функций с одинаковым количеством аргументов (sol будет заблаговременно исключать все функции, не соответствующие количеству аргументов).
3744
3745« As_returns :: Содержание :: собственность »
3746
3747пространство имен стека
3748слой абстракции нитро-песчаного ядра над Lua
3749
3750namespace stack
3751Если вы обнаружите, что абстракции более высокого уровня не соответствуют вашим потребностям, вы, возможно, захотите углубиться в stackпространство имен, чтобы попытаться получить больше от sol. stack.hppа stackпространство имен определяет несколько утилит для работы с Lua, включая утилиты push / popping, геттеры, средства проверки типов, помощники вызовов Lua и многое другое. Это пространство имен не документировано полностью, так как большая часть его интерфейса является ртутной и может меняться между выпусками, либо сильно повышать производительность, либо улучшать sol api .
3752
3753Работу на этом уровне стека можно улучшить, если понять, как работает стек Lua в целом, а затем дополнить его объектами и предметами.
3754
3755Однако есть несколько точек настройки ADL, которые вы можете использовать для своих целей, и несколько потенциально полезных функций. Это может помочь, если вы пытаетесь уменьшить объем кода, который вам нужно написать, или если вы хотите, чтобы ваши типы по-разному вели себя в стеке sol. Обратите внимание, что переопределение значений по умолчанию может привести к отказу от многих гарантий безопасности, которые предоставляет sol: поэтому изменяйте точки расширения по своему усмотрению.
3756
3757структуры
3758структура: запись
3759struct record {
3760 int last;
3761 int used;
3762
3763 void use(int count);
3764};
3765Эта структура предназначена для расширенного использования с stack :: get и stack :: check_get . При переопределении точек настройки важно вызвать useфункцию-член этого класса с количеством вещей, которые вы вытаскиваете из стека. usedсодержит общее накопление произведенных предметов. lastэто количество элементов, полученных из стека с последней операцией (не обязательно извлеченных из стека). Во всех тривиальных случаях для типов и после операции; структуры, такие как и могут тянуть больше в зависимости от классов, которые он содержит.last == 1used == 1pairtuple
3766
3767При переопределении точек настройки обратите внимание, что эта структура должна позволять вам помещать несколько возвращаемых значений и получать несколько возвращаемых значений в стек, и, таким образом, иметь возможность беспрепятственно упаковать / распаковать возвращаемые значения из Lua в одну структуру C ++ и наоборот. наоборот. Эта функция рекомендуется только для людей, которым необходимо настроить библиотеку дальше, чем основы. Это также хороший способ добавить поддержку для типа и предложить его обратно в исходную библиотеку, чтобы другие могли получить пользу от вашей работы.
3768
3769Обратите внимание, что настройки также можно разместить здесь на отдельной странице, если отдельные лица решат сделать детальные настройки для своей структуры или других мест.
3770
3771структура: зонд
3772struct probe {
3773 bool success;
3774 int levels;
3775
3776 probe(bool s, int l);
3777 operator bool() const;
3778};
3779Эта структура используется для того, чтобы показать, было ли успешное исследование get_field или нет.
3780
3781члены
3782функция: call_lua
3783template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
3784inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs);
3785Эта функция полезна, когда вы связываете к сырому функции C , но нужны абстракции SOL, чтобы спасти вас агонию настройки аргументов и знать , как вызов функций C работает . startПараметр указывает функцию , где начать вытягивать аргументы. Параметр fx - это то, что должно называться. Дополнительные аргументы передаются функции напрямую. Существуют промежуточные версии этого ( sol::stack::call_into_luaи аналогичного) для более продвинутых пользователей, но они не документированы, поскольку они могут быть изменены для повышения производительности или соответствующей корректировки API в последующих итерациях sol3. Используйте более продвинутые версии на свой страх и риск.
3786
3787функция: получить
3788template <typename T>
3789auto get( lua_State* L, int index = -1 )
3790template <typename T>
3791auto get( lua_State* L, int index, record& tracking )
3792Получает значение объекта indexв стеке. Тип возвращаемого значения зависит от T: с примитивными типами обычно это так T: для всех нераспознанных Tэто, как правило, T&точка расширения, возвращаемая реализацией sol_lua_get <T> . Тип Tпроверяется один раз, как есть (с constоставленными в покое и ссылочными квалификаторами), а затем еще раз, когда он удаляетconst квалификаторы верхнего уровня и модификаторы ссылок, прежде чем перенаправлять их в функцию sol_lua_get <T> точки расширения . stack::getпо умолчанию будет пересылать все аргументы в функцию stack :: check_get с обработчиком, type_panicчтобы сильно предупреждать об ошибках, если вы просите о безопасности,
3793
3794Вы также можете извлечь sol :: необязательный <T> из этого, чтобы он пытался не выдавать ошибки при выполнении get, а тип неверный.
3795
3796функция: проверить
3797template <typename T>
3798bool check( lua_State* L, int index = -1 )
3799
3800template <typename T, typename Handler>
3801bool check( lua_State* L, int index, Handler&& handler )
3802
3803template <typename T, typename Handler>
3804bool check( lua_State* L, int index, Handler&& handler, record& tracking )
3805Проверяет, имеет ли объект indexтип T. Если это не так , он будет вызывать handlerфункцию с , , и в качестве аргументов (и , возможно , с 5 - го аргумента строки . Если вы не передаете свой собственный обработчик, обработчик будет пройдена.lua_State* Lint indexsol::type expectedsol::type actualsol::string_view messageno_panic
3806
3807функция: get_usertype
3808template <typename T>
3809auto get_usertype( lua_State* L, int index = -1 )
3810template <typename T>
3811auto get_usertype( lua_State* L, int index, record& tracking )
3812Непосредственно пытается повторно получить тип, Tиспользуя механизмы пользовательского типа sol3. Аналогично обычному getдля определенного пользователем типа. Полезно, когда вам нужно получить доступ к механизму получения пользовательских типов в sol3 и в то же время обеспечить собственную настройку .
3813
3814функция: check_usertype
3815template <typename T>
3816bool check_usertype( lua_State* L, int index = -1 )
3817
3818template <typename T, typename Handler>
3819bool check_usertype( lua_State* L, int index, Handler&& handler )
3820
3821template <typename T, typename Handler>
3822bool check_usertype( lua_State* L, int index, Handler&& handler, record& tracking )
3823Проверяет, имеет ли объект at indexтип Tи сохраняется ли он как пользовательский тип sol3. Полезно, когда вам нужно получить доступ к механизму проверки пользовательских типов sol3, в то же время предоставляя свои собственные настройки .
3824
3825функция: check_get
3826template <typename T>
3827auto check_get( lua_State* L, int index = -1 )
3828template <typename T, typename Handler>
3829auto check_get( lua_State* L, int index, Handler&& handler, record& tracking )
3830Получает значение объекта indexв стеке, но делает это безопасно. Возвращает optional<U>, где Uв данном случае это тип возвращаемого значения stack::get<T>. Это позволяет человеку должным образом проверить, является ли тип, который он получает, тем, что он на самом деле хочет, и изящно обрабатывать ошибки при работе со стеком, если он того пожелает. Вы можете SOL_ALL_SAFETIES_ONвключить дополнительную безопасность , в которой по stack::getумолчанию будет вызываться эта версия функции с некоторым вариантом обработчика, sol::type_panic_stringчтобы сильно предупреждать об ошибках и помогать вам отслеживать ошибки, если вы подозреваете, что в вашей системе что-то идет не так.
3831
3832функция: нажать
3833// push T inferred from call site, pass args... through to extension point
3834template <typename T, typename... Args>
3835int push( lua_State* L, T&& item, Args&&... args )
3836
3837// push T that is explicitly specified, pass args... through to extension point
3838template <typename T, typename Arg, typename... Args>
3839int push( lua_State* L, Arg&& arg, Args&&... args )
3840
3841// recursively call the the above "push" with T inferred, one for each argument
3842template <typename... Args>
3843int multi_push( lua_State* L, Args&&... args )
3844Основываясь на том, как он вызывается, помещает в стек переменное количество объектов. в 99% случаев возвращает 1 объект, помещенный в стек. В случае a tuple<...>он рекурсивно выталкивает каждый объект, содержащийся в кортеже, слева направо, в результате чего в стек помещается переменное число вещей (это позволяет многозначные возвраты при привязке функции C ++ к Lua). Может вызываться с аргументами, отличающимися от типа, который хочет выдвинуть, или откуда будет выведен вывод . Окончательная форма этой функции , которая будет вызывать один для каждого аргумента. То, что описывает то, что нажать, сначала очищается путем удаления верхнего уровня.sol::stack::push<T>( L, args... )sol::stack::push( L, arg, args... )Targsol::stack::multi_pushsol::stack::pushTconstквалификаторы и эталонные квалификаторы перед отправкой в точку расширения sol_lua_push <T> .
3845
3846функция: push_reference
3847// push T inferred from call site, pass args... through to extension point
3848template <typename T, typename... Args>
3849int push_reference( lua_State* L, T&& item, Args&&... args )
3850
3851// push T that is explicitly specified, pass args... through to extension point
3852template <typename T, typename Arg, typename... Args>
3853int push_reference( lua_State* L, Arg&& arg, Args&&... args )
3854
3855// recursively call the the above "push" with T inferred, one for each argument
3856template <typename... Args>
3857int multi_push_reference( lua_State* L, Args&&... args )
3858Эти функции ведут себя аналогично приведенным выше, но они проверяют определенные критерии и вместо этого пытаются выдвинуть ссылку, а не принудительно копировать копию, если это необходимо. Используйте его осторожно, так как sol3 использует это главным образом как возврат из функций и переменных пользовательского типа, чтобы сохранить семантику цепочки / переменной от этого объекта класса. Его внутренние компоненты обновляются в соответствии с потребностями sol3, и, хотя он, как правило, делает «правильные вещи» и его не нужно менять какое-то время, sol3 оставляет за собой право изменять свои внутренние механизмы обнаружения в соответствии с потребностями своих пользователей в любое время, как правило, без нарушения обратной совместимости и ожиданий, но не совсем гарантировано.
3859
3860функция: поп
3861template <typename... Args>
3862auto pop( lua_State* L );
3863Выталкивает объект из стека Удалит фиксированное количество объектов из стека, как правило, определяется sol::lua_size<T>чертами предоставленных аргументов. Обычно это функция простоты, используемая для удобства.
3864
3865функция: верх
3866int top( lua_State* L );
3867Возвращает количество значений в стеке.
3868
3869функция: set_field
3870template <bool global = false, typename Key, typename Value>
3871void set_field( lua_State* L, Key&& k, Value&& v );
3872
3873template <bool global = false, typename Key, typename Value>
3874void set_field( lua_State* L, Key&& k, Value&& v, int objectindex);
3875Устанавливает поле, на которое ссылается ключ, kна заданное значение v, помещая ключ в стек, помещая значение в стек, а затем выполняя эквивалент lua_setfieldобъекта для данного значения objectindex. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
3876
3877функция: get_field
3878template <bool global = false, typename Key>
3879void get_field( lua_State* L, Key&& k [, int objectindex] );
3880Получает поле, на которое ссылается ключ k, путем нажатия ключа на стек и затем выполнения эквивалента lua_getfield. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
3881
3882Эта функция оставляет полученное значение в стеке.
3883
3884функция: probe_get_field
3885template <bool global = false, typename Key>
3886probe probe_get_field( lua_State* L, Key&& k [, int objectindex] );
3887Получает поле, на которое ссылается ключ k, путем нажатия ключа на стек и затем выполнения эквивалента lua_getfield. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный. Кроме того, он делает это безопасно, входя только на столько уровней, насколько это возможно: если возвращаемое значение не является чем-то, что может быть проиндексировано, тогда запросы обхода с tuple/ pairпрекратят работу раньше и вернут зондирующую информацию со структурой зонда .
3888
3889Эта функция оставляет полученное значение в стеке.
3890
3891объекты (точки расширения)
3892Вы можете настроить способ, которым sol обрабатывает различные структуры и классы, следуя информации, представленной в добавлении ваших собственных типов .
3893
3894Ниже приведена более обширная информация для любознательных.
3895
3896Точка расширения ADL sol_lua_get
3897MyType sol_lua_get ( sol::types<MyType>, lua_State* L, int index, sol::stack::record& tracking ) {
3898 // do work
3899 // ...
3900
3901 return MyType{}; // return value
3902}
3903Эта точка расширения относится к getобъекту (или ссылке, или указателю, или какому-либо другому) типа Tили к чему-то, что может быть преобразовано в него. Внутренняя реализация getter по умолчанию предполагает, Tчто это тип пользователя, и извлекает данные пользователя из Lua, прежде чем пытаться привести их к желаемому T.
3904
3905В целом, есть реализации для получения чисел (типа is_floating, is_integralсовпадающих по типу), получения stringи добавления широких строковых и юникодных вариантов, получения необработанных пользовательских данных с помощью userdata_value и чего угодно, как upvalues с upvalue_index , получения необработанных lua_CFunction s и, наконец, извлечения функций Lua в . Он также определен для всего, что происходит от sol :: reference . У этого также есть специальная реализация для 2 умных указателей стандартной библиотеки (см. Память типа пользователя ), которая может быть более конкретно расширена.const char*function<R(Args...)>
3906
3907Точка расширения ADL sol_lua_push
3908int push ( sol::types<MyType>, lua_State* L, MyType&& value ) {
3909 // can optionally take more than just 1 argument
3910 // to "construct" in-place and similar
3911 // use them however you like!
3912 // ...
3913 return N; // number of things pushed onto the stack
3914}
3915Эта точка расширения является pushзначением в Lua. Возвращает количество вещей, помещенных в стек. Реализация по умолчанию предполагает, Tчто это пользовательский тип, и помещает пользовательские данные в Lua с привязкой к ним специфической для класса метатаблицы в масштабе штата. Есть реализации толкания чисел ( is_floating, is_integralСопоставления типов), получение stringи , получая сырой UserData с UserData и сырьем upvalues с повышать стоимость , получая сырой lua_CFunction с, и , наконец , вытаскивая функцию Lua в . Он также определен для всего, что происходит от sol :: reference . У этого также есть специальная реализация для 2 умных указателей стандартной библиотеки (см. Память типа пользователя)const char*sol::function).
3916
3917Точка расширения ADL sol_lua_check
3918template <typename Handler>
3919bool sol_lua_check ( sol::types<MyType>, lua_State* L, int index, Handler&& handler, sol::stack::record& tracking ) {
3920 // if the object in the Lua stack at index is a T, return true
3921 if ( ... ) {
3922 tracking.use(1); // or however many you use
3923 return true;
3924 }
3925 // otherwise, call the handler function,
3926 // with the required 4/5 arguments, then return false
3927 //
3928 handler(L, index, expected, indextype, "message");
3929 return false;
3930}
3931Эта точка расширения заключается в checkтом, является ли тип по данному индексу тем, чем он должен быть. Реализация по умолчанию просто проверяет, равен ли ожидаемый тип, переданный через шаблон, типу объекта по указанному индексу в стеке Lua. Реализация по умолчанию для типов, которые рассматриваются, userdataпроходит множество проверок, чтобы поддержать проверку, является ли тип действительно типом Tили является ли он базовым классом того, что он на самом деле хранит как пользовательские данные в этом индексе.
3932
3933Обратите внимание, что вы можете
3934
3935Точка расширения ADL sol_lua_interop_check
3936template <typename T, typename Handler>
3937bool sol_lua_interop_check(sol::types<T>, lua_State* L, int relindex, sol::type index_type, Handler&& handler, sol::stack::record& tracking) {
3938 // implement custom checking here for a userdata:
3939 // if it doesn't match, return "false" and regular
3940 // sol userdata checks will kick in
3941 return false;
3942 // returning true will skip sol's
3943 // default checks
3944}
3945Эта точка расширения относится к checkсторонним данным пользователя. Он должен возвращаться, trueесли тип соответствует некоторой пользовательской спецификации пользовательских данных (скажем, из другой библиотеки или внутренней структуры), и falseесли нет. Реализация по умолчанию просто возвращается, falseчтобы позволить исходным обработчикам sol3 позаботиться обо всем. Если вы хотите реализовать свою собственную проверку пользовательских типов; например, для возни с toLuaили OOLuaили kaguyaили некоторыми другими библиотеками. Обратите внимание, что библиотека должна иметь макет с совместимой памятью, если вы хотите специализировать этот метод проверки, но не последующий метод получения . Вы можете специализировать его, как показано в примерах взаимодействия .
3946
3947Заметка
3948
3949Вы должны включить эту функцию с помощью SOL_ENABLE_INTEROP, как описано в разделе конфигурации и безопасности .
3950
3951Точка расширения ADL sol_lua_interop_get
3952template <typename T>
3953pair<bool, T*> sol_lua_interop_get(sol::types<T> t, lua_State* L, int relindex, void* unadjusted_pointer, sol::stack::record& tracking) {
3954 // implement custom getting here for non-sol3 userdatas:
3955 // if it doesn't match, return "false" and regular
3956 // sol userdata getters will kick in
3957 return { false, nullptr };
3958}
3959Эта точка расширения относится к getсторонним данным пользователя. Он должен возвращать оба trueи настроенный указатель, если тип соответствует некоторой пользовательской спецификации пользовательских данных (скажем, из другой библиотеки или внутренней структуры). Реализация по умолчанию просто возвращается, чтобы позволить стандартной реализации sol3 позаботиться обо всем. Вы можете использовать его для взаимодействия с другими платформами, которые не являются sol3, но все еще включают их силу; например, для возни с или некоторых других библиотек. Вы можете специализировать его, как показано в примерах взаимодействия .{ false, nullptr }kaguya
3960
3961Заметка
3962
3963Вы должны включить его с помощью SOL_ENABLE_INTEROP, как описано в разделе конфигурации и безопасности .
3964
3965Заметка
3966
3967Вам НЕ нужно использовать этот метод, в частности, если расположение памяти совместимо. (Например, toLuaхранит пользовательские данные в sol3-совместимом способе.)
3968
3969нить
3970отдельное состояние, которое может содержать и запускать функции
3971
3972class thread : public reference { /* ... */ };
3973sol::threadэто отдельная исполняемая часть виртуальной машины Lua, которую можно использовать для выполнения работы отдельно от основного потока, например, с сопрограммами . Чтобы взять таблицу или сопрограмму и запустить ее специально на том, что sol::threadвы извлекли из lua или создали, просто получите эту функцию через состояние потока
3974
3975Заметка
3976
3977Поток ЦП не всегда эквивалентен новому потоку в Lua: this_thread::get_id()может быть одинаковым для 2 обратных вызовов, которые имеют 2 различных потока Lua. Чтобы узнать, из какого потока был вызван обратный вызов, подключитесь к sol :: this_state из своего обратного вызова Lua, а затем создайте a sol::thread, передавая sol::this_stateдля первого и последнего аргументов. Затем изучите результаты статуса и is_...звонков ниже.
3978
3979свободная функция
3980функция: main_thread
3981main_thread(lua_State* current, lua_State* backup_if_bad_platform = nullptr);
3982Функция извлекает основной поток приложения на Lua 5.2 и выше только . Он предназначен для кода, который должен учитывать многопоточность (например, использует несколько потоков и сопрограмм ).sol::main_thread( ... )
3983
3984Предупреждение
3985
3986Эта кодовая функция будет присутствовать в Lua 5.1 / LuaJIT, но будет иметь правильное поведение только при наличии одного аргумента в Lua 5.2 и выше. Lua 5.1 не поддерживает извлечение основного потока из его реестра, и поэтому полностью рекомендуется, если вы пишете кросс-платформенный код Lua, что вы должны хранить основной поток вашего приложения в некотором глобальном хранилище, доступном где-либо. Затем передайте этот элемент в и он будет выбирать его каждый раз. Если вы не собираетесь использовать Lua 5.1 / LuaJIT, вы можете игнорировать последний параметр.sol::main_thread( possibly_thread_state, my_actual_main_state )my_actual_main_state
3987
3988члены
3989конструктор: резьба
3990thread(stack_reference r);
3991thread(lua_State* L, int index = -1);
3992thread(lua_State* L, lua_State* actual_thread);
3993Извлекает поток из стека Lua по указанному индексу и позволяет человеку использовать все содержащиеся в нем абстракции. Также может потребоваться фактическое состояние потока, чтобы создать поток из этого.
3994
3995функция: просмотр состояния thread_state ()
3996state_view state() const;
3997Это извлекает текущее состояние потока, создавая представление state_view, которым можно манипулировать, как и любым другим. Сопрограммы, извлеченные из Lua с использованием состояния потока, будут запускаться именно для этого потока.
3998
3999функция: получить объект состояния потока
4000lua_State* thread_state () const;
4001Эта функция извлекает тот, lua_State*который представляет поток.
4002
4003текущий статус потока
4004thread_status status () const;
4005Извлекает состояние потока, которое описывает текущее состояние потока.
4006
4007статус основного потока
4008bool is_main_thread () const;
4009Проверяет, является ли поток основным потоком Lua.
4010
4011функция: создание потока
4012thread create();
4013static thread create (lua_State* L);
4014Создает новый поток из данного а lua_State*.
4015
4016« Object :: Contents :: необязательный <T> »
4017
4018сопрограмма
4019Возобновляемые / уступающие функции от Lua
4020
4021A coroutine- это ссылка на функцию в Lua, которую можно вызывать несколько раз, чтобы получить конкретный результат. Он запускается в lua_State, который использовался для его создания (см. Поток для примера того, как получить сопрограмму, которая работает в потоке, отдельном от вашего обычного «основного» lua_State ).
4022
4023coroutineОбъект полностью аналогичен protected_function объекта, с дополнительными функциями - членами , чтобы проверить , если сопрограмма дал ( call_status :: выданное ) , и, таким образом , снова работоспособной, была ли она завершена ( call_status :: ОК ) и , следовательно , не может дать больше значения, или произошла ошибка (см. коды ошибок status () и call_status ).
4024
4025Например, вы можете работать с сопрограммой следующим образом:
4026
4027co.lua
4028 function loop()
4029 while counter ~= 30
4030 do
4031 coroutine.yield(counter);
4032 counter = counter + 1;
4033 end
4034 return counter
4035 end
4036Это функция, которая дает:
4037
4038main.cpp
4039sol::state lua;
4040lua.open_libraries(sol::lib::base, sol::lib::coroutine);
4041lua.script_file("co.lua");
4042sol::coroutine cr = lua["loop"];
4043
4044for (int counter = 0; // start from 0
4045 counter < 10 && cr; // we want 10 values, and we only want to run if the coroutine "cr" is valid
4046 // Alternative: counter < 10 && cr.valid()
4047 ++counter) {
4048 // Call the coroutine, does the computation and then suspends
4049 int value = cr();
4050}
4051Обратите внимание, что этот код не проверяет наличие ошибок: для этого вы можете вызвать функцию и назначить ее как , а затем проверить, как в случае с protected_function . Наконец, вы можете запустить эту сопрограмму в другом потоке, выполнив следующие действия:auto result = cr();result.valid()
4052
4053main_with_thread.cpp
4054sol::state lua;
4055lua.open_libraries(sol::lib::base, sol::lib::coroutine);
4056lua.script_file("co.lua");
4057sol::thread runner = sol::thread::create(lua.lua_state());
4058sol::state_view runnerstate = runner.state();
4059sol::coroutine cr = runnerstate["loop"];
4060
4061for (int counter = 0; counter < 10 && cr; ++counter) {
4062 // Call the coroutine, does the computation and then suspends
4063 int value = cr();
4064}
4065Ниже приведены члены sol::coroutine:
4066
4067члены
4068функция: конструктор
4069coroutine(lua_State* L, int index = -1);
4070Хватает сопрограмму по указанному индексу с учетом lua_State*.
4071
4072возвращение статуса сопрограммы
4073call_status status() const noexcept;
4074Возвращает статус сопрограммы.
4075
4076проверяет на ошибку
4077bool error() const noexcept;
4078Проверяет, произошла ли ошибка при запуске сопрограммы.
4079
4080выполняемый и явный оператор bool
4081bool runnable () const noexcept;
4082explicit operator bool() const noexcept;
4083Эти функции позволяют проверить, можно ли еще вызывать сопрограмму (имеет больше значений для выдачи и не имеет ошибок). Если у вас есть объект сопрограммы , вы можете проверить или сделать .coroutine my_co = /*...*/runnable()if ( my_co ) { /* use coroutine */ }
4084
4085вызывая сопрограмму
4086template<typename... Args>
4087protected_function_result operator()( Args&&... args );
4088
4089template<typename... Ret, typename... Args>
4090decltype(auto) call( Args&&... args );
4091
4092template<typename... Ret, typename... Args>
4093decltype(auto) operator()( types<Ret...>, Args&&... args );
4094Вызывает сопрограмму. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Затем проверьте дополнительную информацию об успешном выполнении или просто проверьте объект сопрограммы в сообщении ifs, как показано выше .my_co(sol::types<int, string>, ...)status()
4095
4096« Protected_function :: Contents :: yielding »
4097
4098функции и вы
4099Sol может регистрировать все виды функций. Многие из них показаны в быстром 'n' грязном , но здесь мы обсудим множество дополнительных способов регистрации функций в системе Lua, обернутой в sol.
4100
4101Установка новой функции
4102Имея функцию C ++, вы можете поместить ее в sol несколькими эквивалентными способами, работая аналогично тому, как работает установка переменных :
4103
4104Регистрация функций C ++
4105
4106#include <sol/sol.hpp>
4107
4108string my_function( int a, string b ) {
4109 // Create a string with the letter 'D' "a" times,
4110 // append it to 'b'
4111 return b + string( 'D', a );
4112}
4113
4114int main () {
4115
4116 sol::state lua;
4117
4118 lua["my_func"] = my_function; // way 1
4119 lua.set("my_func", my_function); // way 2
4120 lua.set_function("my_func", my_function); // way 3
4121
4122 // This function is now accessible as 'my_func' in
4123 // lua scripts / code run on this state:
4124 lua.script("some_str = my_func(1, 'Da')");
4125
4126 // Read out the global variable we stored in 'some_str' in the
4127 // quick lua code we just executed
4128 string some_str = lua["some_str"];
4129 // some_str == "DaD"
4130}
4131Один и тот же код работает со всеми видами функций, начиная с указателей на функции / переменные-члены, которые есть у вас в классе, а также с лямбдами:
4132
4133Регистрация функций-членов C ++
4134
4135struct my_class {
4136 int a = 0;
4137
4138 my_class(int x) : a(x) {
4139
4140 }
4141
4142 int func() {
4143 ++a; // increment a by 1
4144 return a;
4145 }
4146};
4147
4148int main () {
4149
4150 sol::state lua;
4151
4152 // Here, we are binding the member function and a class instance: it will call the function on
4153 // the given class instance
4154 lua.set_function("my_class_func", &my_class::func, my_class());
4155
4156 // We do not pass a class instance here:
4157 // the function will need you to pass an instance of "my_class" to it
4158 // in lua to work, as shown below
4159 lua.set_function("my_class_func_2", &my_class::func);
4160
4161 // With a pre-bound instance:
4162 lua.script(R"(
4163 first_value = my_class_func()
4164 second_value = my_class_func()
4165 )");
4166 // first_value == 1
4167 // second_value == 2
4168
4169 // With no bound instance:
4170 lua.set("obj", my_class(24));
4171 // Calls "func" on the class instance
4172 // referenced by "obj" in Lua
4173 lua.script(R"(
4174 third_value = my_class_func_2(obj)
4175 fourth_value = my_class_func_2(obj)
4176 )");
4177 // first_value == 25
4178 // second_value == 26
4179}
4180Функции класса-члена и переменные класса-члена будут превращены в функции при установке таким образом. Вы можете получить интуитивно понятную переменную с доступом после этого раздела, когда узнаете о пользовательских типах для C ++ в Lua , но сейчас мы просто имеем дело с функциями!obj.a = value
4181
4182Другой вопрос, который возникает у многих людей, касается шаблонов функций. Шаблоны функций - функции-члены или свободные функции - не могут быть зарегистрированы, потому что они не существуют, пока вы не создадите их в C ++. Поэтому, учитывая шаблонную функцию, такую как:
4183
4184Шаблонная функция C ++
41851
41862
41873
41884
4189template <typename A, typename B>
4190auto my_add( A a, B b ) {
4191 return a + b;
4192}
4193Вы должны указать все аргументы шаблона, чтобы связать и использовать его, вот так:
4194
4195Регистрация инстанциации шаблона функции
4196
4197int main () {
4198
4199 sol::state lua;
4200
4201 // adds 2 integers
4202 lua["my_int_add"] = my_add<int, int>;
4203
4204 // concatenates 2 strings
4205 lua["my_string_combine"] = my_add<string, string>;
4206
4207 lua.script("my_num = my_int_add(1, 2)");
4208 int my_num = lua["my_num"];
4209 // my_num == 3
4210
4211 lua.script("my_str = my_string_combine('bark bark', ' woof woof')");
4212 string my_str = lua["my_str"];
4213 // my_str == "bark bark woof woof"
4214}
4215Обратите внимание, что мы связываем две отдельные функции. Что если мы хотим связать только одну функцию, но она будет вести себя по-разному в зависимости от того, с какими аргументами она вызывается? Это называется перегрузкой, и это можно сделать с помощью sol :: overload следующим образом:
4216
4217Регистрация экземпляров шаблона функции C ++
4218 1
4219 2
4220 3
4221 4
4222 5
4223 6
4224 7
4225 8
4226 9
422710
422811
422912
423013
423114
4232int main () {
4233
4234 sol::state lua;
4235
4236 // adds 2 integers
4237 lua["my_combine"] = sol::overload( my_add<int, int>, my_add<string, string> );
4238
4239 lua.script("my_num = my_combine(1, 2)");
4240 lua.script("my_str = my_combine('bark bark', ' woof woof')");
4241 int my_num = lua["my_num"];
4242 string my_str = lua["my_str"];
4243 // my_num == 3
4244 // my_str == "bark bark woof woof"
4245}
4246Это полезно для функций, которые могут принимать несколько типов и должны вести себя по-разному в зависимости от этих типов. Вы можете установить столько перегрузок, сколько хотите, и они могут быть разных типов.
4247
4248В качестве примечания, связывание функций с параметрами по умолчанию не связывает по волшебству несколько версий функции, вызываемой с параметрами по умолчанию. Вместо этого вы должны использовать sol :: overload .
4249
4250В качестве примечания, пожалуйста, убедитесь, что понимаете Убедитесь, что вы понимаете последствия привязки лямбда / вызываемой структуры различными способами и что это значит для вашего кода!
4251
4252Получение функции от Lua
4253Есть 2 способа получить функцию от Lua. Один с sol :: function, а другой - более продвинутая оболочка с sol :: protected_function . Используйте их для извлечения вызываемых из Lua и вызова основной функции двумя способами:
4254
4255Получение sol :: function
4256 1
4257 2
4258 3
4259 4
4260 5
4261 6
4262 7
4263 8
4264 9
426510
426611
426712
426813
426914
427015
427116
427217
427318
427419
4275int main () {
4276
4277 sol::state lua;
4278
4279 lua.script(R"(
4280 function f (a)
4281 return a + 5
4282 end
4283 )");
4284
4285 // Get and immediately call
4286 int x = lua["f"](30);
4287 // x == 35
4288
4289 // Store it into a variable first, then call
4290 sol::function f = lua["f"];
4291 int y = f(20);
4292 // y == 25
4293}
4294В Lua вы можете получить все, что можно вызвать, включая функции C ++, которые вы используете, set_functionили аналогичные. sol::protected_functionведет себя аналогично sol::function, но имеет переменную error_handler, которую вы можете установить в функцию Lua. Это ловит все ошибки и запускает их через функцию обработки ошибок:
4295
4296Получение sol :: protected_function
4297int main () {
4298 sol::state lua;
4299
4300 lua.script(R"(
4301 function handler (message)
4302 return "Handled this message: " .. message
4303 end
4304
4305 function f (a)
4306 if a < 0 then
4307 error("negative number detected")
4308 end
4309 return a + 5
4310 end
4311 )");
4312
4313 sol::protected_function f = lua["f"];
4314 f.error_handler = lua["handler"];
4315
4316 sol::protected_function_result result = f(-500);
4317 if (result.valid()) {
4318 // Call succeeded
4319 int x = result;
4320 }
4321 else {
4322 // Call failed
4323 sol::error err = result;
4324 string what = err.what();
4325 // 'what' Should read
4326 // "Handled this message: negative number detected"
4327 }
4328}
4329Несколько возвратов в и из Lua
4330Вы можете вернуть несколько предметов в Lua и из него, используя tuple/ pairклассы, предоставляемые C ++. Это позволяет вам также использовать sol :: tie для установки возвращаемых значений в предварительно объявленные элементы. Чтобы получить несколько возвратов, просто запросите tupleтип из результата вычисления функции или sol::tieсвязку предварительно объявленных переменных вместе и установите результат, равный этому:
4331
4332Несколько возвратов от Lua
4333 1
4334 2
4335 3
4336 4
4337 5
4338 6
4339 7
4340 8
4341 9
434210
434311
434412
434513
434614
434715
4348int main () {
4349 sol::state lua;
4350
4351 lua.script("function f (a, b, c) return a, b, c end");
4352
4353 tuple<int, int, int> result;
4354 result = lua["f"](1, 2, 3);
4355 // result == { 1, 2, 3 }
4356 int a, int b;
4357 string c;
4358 sol::tie( a, b, c ) = lua["f"](1, 2, "bark");
4359 // a == 1
4360 // b == 2
4361 // c == "bark"
4362}
4363Вы также можете вернуть несколько элементов самостоятельно из связанной с C ++ функции. Здесь мы собираемся связать лямбду C ++ с Lua, а затем вызвать ее через Lua и получить tupleвыход с другой стороны:
4364
4365Многократное возвращение в Lua
4366int main () {
4367 sol::state lua;
4368
4369 lua["f"] = [](int a, int b, sol::object c) {
4370 // sol::object can be anything here: just pass it through
4371 return make_tuple( a, b, c );
4372 };
4373
4374 tuple<int, int, int> result = lua["f"](1, 2, 3);
4375 // result == { 1, 2, 3 }
4376
4377 tuple<int, int, string> result2;
4378 result2 = lua["f"](1, 2, "Arf?")
4379 // result2 == { 1, 2, "Arf?" }
4380
4381 int a, int b;
4382 string c;
4383 sol::tie( a, b, c ) = lua["f"](1, 2, "meow");
4384 // a == 1
4385 // b == 2
4386 // c == "meow"
4387}
4388Обратите внимание, что мы используем sol :: object для переноса через «любое значение» из Lua. Вы также можете использовать sol::make_objectдля создания объекта из некоторого значения, чтобы он также мог быть возвращен в Lua.
4389
4390Любое возвращение в и из Lua
4391На это намекали в предыдущем примере кода, но sol::objectэто хороший способ передать «любой тип» обратно в Lua (пока мы все ждем, variant<...>чтобы его реализовали и отправили разработчики компилятора / библиотеки C ++).
4392
4393Он может быть использован как так, в сочетании с sol::this_state:
4394
4395Верни что-нибудь в Луа
4396 1
4397 2
4398 3
4399 4
4400 5
4401 6
4402 7
4403 8
4404 9
440510
440611
440712
440813
440914
441015
441116
441217
441318
441419
441520
441621
441722
441823
441924
442025
442126
442227
4423sol::object fancy_func (sol::object a, sol::object b, sol::this_state s) {
4424 sol::state_view lua(s);
4425 if (a.is<int>() && b.is<int>()) {
4426 return sol::make_object(lua, a.as<int>() + b.as<int>());
4427 }
4428 else if (a.is<bool>()) {
4429 bool do_triple = a.as<bool>();
4430 return sol::make_object(lua, b.as<double>() * ( do_triple ? 3 : 1 ) );
4431 }
4432 return sol::make_object(lua, sol::lua_nil);
4433}
4434
4435int main () {
4436 sol::state lua;
4437
4438 lua["f"] = fancy_func;
4439
4440 int result = lua["f"](1, 2);
4441 // result == 3
4442 double result2 = lua["f"](false, 2.5);
4443 // result2 == 2.5
4444
4445 // call in Lua, get result
4446 lua.script("result3 = f(true, 5.5)");
4447 double result3 = lua["result3"];
4448 // result3 == 16.5
4449}
4450Это охватывает почти все, что вам нужно знать о функциях и о том, как они взаимодействуют с sol. Для некоторых продвинутых уловок и изящных вещей, проверьте sol :: this_state и sol :: variadic_args . Следующая остановка в этом уроке о типах C ++ (usertypes) в Lua ! Если вам нужно немного больше информации о функциях на стороне C ++ и о том, как наилучшим образом использовать аргументы из C ++, см. Это примечание .
4451
4452« Переменные :: содержание
4453перегрузка
4454вызов различных функций в зависимости от номера / типа аргумента
4455
4456функция: создать перегруженный набор
44571
44582
44593
44604
44615
4462template <typename... Args>
4463struct overloaded_set : tuple<Args...> { /* ... */ };
4464
4465template <typename... Args>
4466overloaded_set<Args...> overload( Args&&... args );
4467Фактически созданный класс по sol::overloadсути является оберткой типов, tupleкоторая сообщает библиотеке, что создается перегрузка. Функция помогает пользователям создавать перегруженные функции, которые можно вызывать из Lua, используя 1 имя, но несколько аргументов. Он предназначен для замены спагетти кода, где пользователи макетируют это, делая странные операторы if и переключая, какую версию функции вызывать на основе luaL_check {number / udata / string} .
4468
4469Заметка
4470
4471Обратите внимание, что параметры по умолчанию в функции (например, ) не существуют вне забавы C ++ во время компиляции. Когда эта функция связывается или сериализуется в инфраструктуру Lua, она связывается как функция, принимающая 1 аргумент, а не 2 функции, принимающие либо 0, либо 1 аргумент. Если вы хотите добиться того же эффекта, вам нужно использовать перегрузку и явно вызывать ту версию функции, которую вы хотите. В C ++ нет магии, которая позволяла бы мне получать параметры по умолчанию и устанавливать их автоматически.int func(int a = 20)
4472
4473Заметка
4474
4475Разрешение перегрузки может зависеть от настроек конфигурации на страницах безопасности . Например, невозможно отличить целые числа (uint8_t, in32_t и т. Д.) От типов с плавающей запятой (float, double, half), когда они SOL_SAFE_NUMERICSне включены.
4476
4477Его использование простое: везде, где вы можете передать тип функции в Lua, будь то пользовательский тип или вы просто устанавливаете какую-либо функцию с помощью setили set_function(для таблицы или состояния (_view) ), просто оберните функции, которые вы хотите Рассмотрим разрешение перегрузки для одной функции следующим образом:
4478
4479sol::overload( func1, func2, ... funcN );
4480Функции могут быть любым видом функции / функционального объекта (лямбда). Учитывая эти функции и структуру:
4481
4482 1
4483 2
4484 3
4485 4
4486 5
4487 6
4488 7
4489 8
4490 9
449110
449211
449312
449413
449514
449615
449716
449817
449918
450019
450120
450221
450322
450423
450524
450625
450726
450827
4509#define SOL_ALL_SAFETIES_ON 1
4510#include <sol/sol.hpp>
4511
4512#include "assert.hpp"
4513
4514#include <iostream>
4515
4516struct pup {
4517 int barks = 0;
4518
4519 void bark () {
4520 ++barks; // bark!
4521 }
4522
4523 bool is_cute () const {
4524 return true;
4525 }
4526};
4527
4528void ultra_bark( pup& p, int barks) {
4529 for (; barks --> 0;) p.bark();
4530}
4531
4532void picky_bark( pup& p, string s) {
4533 if ( s == "bark" )
4534 p.bark();
4535}
4536Затем вы используете его так же, как и для любой другой части API:
4537
4538 1
4539 2
4540 3
4541 4
4542 5
4543 6
4544 7
4545 8
4546 9
454710
454811
454912
455013
455114
455215
455316
455417
4555int main () {
4556 cout << "=== overloading with members ===" << endl;
4557
4558 sol::state lua;
4559 lua.open_libraries(sol::lib::base);
4560
4561 lua.set_function( "bark", sol::overload(
4562 ultra_bark,
4563 []() { return "the bark from nowhere"; }
4564 ) );
4565
4566 lua.new_usertype<pup>( "pup",
4567 // regular function
4568 "is_cute", &pup::is_cute,
4569 // overloaded function
4570 "bark", sol::overload( &pup::bark, &picky_bark )
4571 );
4572Выполнение следующих действий в Lua вызовет определенные выбранные перегрузки и связанные с ними функции:
4573 const auto& code = R"(
4574 barker = pup.new()
4575 print(barker:is_cute())
4576 barker:bark() -- calls member function pup::bark
4577 barker:bark("meow") -- picky_bark, no bark
4578 barker:bark("bark") -- picky_bark, bark
4579
4580 bark(barker, 20) -- calls ultra_bark
4581 print(bark()) -- calls lambda which returns that string
4582 )";
4583
4584 lua.script(code);
4585
4586 pup& barker = lua["barker"];
4587 cout << barker.barks << endl;
4588 c_assert(barker.barks == 22);
4589
4590 cout << endl;
4591 return 0;
4592}
4593Заметка
4594
4595Перегрузка выполняется в системе «первым пришел - первым обслужен». Это означает, что если две перегрузки являются совместимыми, работоспособными перегрузками, он выберет первую в списке.
4596
4597Обратите внимание, что из-за этой системы вы можете использовать sol :: variadic_args, чтобы сделать функцию, которая служит «запасным вариантом». Убедитесь, что это последняя указанная функция в списке функций для . Этот пример показывает, как .sol::overload( ... )
4598
4599Заметка
4600
4601Пожалуйста, имейте в виду, что выполнение этого требует затрат времени выполнения, чтобы найти правильную перегрузку. Стоимость напрямую зависит не от количества перегрузок, а от количества функций с одинаковым количеством аргументов (sol будет заблаговременно исключать все функции, не соответствующие количеству аргументов).
4602
4603« As_returns :: Содержание :: собственность »
4604
4605функции
4606работа с функциями в sol3
4607
4608Есть ряд примеров, касающихся функций и того, как их можно связать с sol3:
4609
4610Для более быстрого прохождения, которое демонстрирует почти все, посмотрите примеры и быстрый и грязный учебник
4611Для полного объяснения, прочитайте учебник и проконсультируйтесь с предметами ниже
4612Если у вас есть привязки и настройки, которые хотят использовать C API без вмешательства sol3, вы можете использовать необработанную функцию, которая имеет определенные последствия ( см. Ниже )
4613Вернуть несколько значений в Lua:
4614возвращая tuple
4615используя sol :: variadic_results
4616Вызовы функций перегрузки с различными типами аргументов и рассчитывают на одно имя (перегрузка с первым связыванием, пересылка с первым обслуживанием)
4617Примечание: из-за этой функции автоматическое преобразование числа в строку из Lua не разрешено для перегрузок и не работает, когда включены функции безопасности.
4618Перегрузки int / float должны быть SOL_SAFE_NUMERICSвключены, чтобы различать два
4619Используйте C ++ захваты и лямбды для привязки функций-членов, привязанных к одному объекту /
4620Вы можете работать с прозрачными аргументами, которые предоставляют вам специальную информацию, такую как
4621sol :: variadic_args , для обработки переменного количества аргументов во время выполнения
4622sol :: this_state , для получения текущего состояния Lua
4623sol :: this_environment , для потенциального извлечения текущей среды Lua
4624Управляйте сериализацией аргументов и возвращаемых типов с помощью sol :: nested , sol :: as_table , sol :: as_args и sol :: as_function
4625Установите среды для функций и скриптов Lua с помощью sol :: environment
4626Вы можете использовать политики, чтобы управлять зависимостями и оптимизировать возвращаемые значения, а также применять настраиваемое поведение к возвращаемым функциям.
4627работа с callables / lambdas
4628Чтобы явно указать, что структура должна интерпретироваться как функция, используйте . Вы также можете использовать вызов sol :: as_function , который обернет и идентифицирует ваш тип как функцию.my_table.set_function( key, func_value );
4629
4630Заметка
4631
4632Когда вы устанавливаете lambdas / callables, используя одну и ту же сигнатуру функции, вы можете страдать от данных (таких как строковые литералы) от «неправильного поведения». Это связано с тем, что некоторые компиляторы не предоставляют уникальные имена типов, которые мы можем получить в C ++ с отключенным RTTI, и, таким образом, он будет регистрировать первую лямбду определенной сигнатуры как ту, которая будет вызвана. В результате строковые литералы и другие данные, хранимые способом, определяемым реализацией компилятора, могут быть свернуты и запускать неправильную подпрограмму, даже если другие наблюдаемые побочные эффекты хороши.my_table.set( ... )const static
4633
4634Чтобы избежать этой проблемы, зарегистрируйте все свои лямбды с помощью my_table.set_function и вообще избегайте кошмаров .
4635
4636Кроме того, важно знать, что лямбда-выражения без указанного возвращаемого типа (и неконстантного, не ссылочного auto) будут возвращать возвращаемые значения. Чтобы явно захватить или вернуть ссылки, используйте decltype(auto)или укажите тип возвращаемого значения точно так, как вам нужно:
4637#define SOL_ALL_SAFETIES_ON 1
4638#include <sol/sol.hpp>
4639
4640#include <assert.hpp>
4641
4642int main(int, char*[]) {
4643
4644 struct test {
4645 int blah = 0;
4646 };
4647
4648 test t;
4649 sol::state lua;
4650 lua.set_function("f", [&t]() {
4651 return t;
4652 });
4653 lua.set_function("g", [&t]() -> test& {
4654 return t;
4655 });
4656
4657 lua.script("t1 = f()");
4658 lua.script("t2 = g()");
4659
4660 test& from_lua_t1 = lua["t1"];
4661 test& from_lua_t2 = lua["t2"];
4662
4663 // not the same: 'f' lambda copied
4664 c_assert(&from_lua_t1 != &t);
4665 // the same: 'g' lambda returned reference
4666 c_assert(&from_lua_t2 == &t);
4667
4668 return 0;
4669}
4670исключительная безопасность / обработка
4671Все функции, связанные с sol3, устанавливают батут исключений вокруг функции (если вы не работаете с необработанной функцией lua_CF, которую вы выдвинули сами ). protected_function также имеет элемент-обработчик ошибок и батут исключений вокруг своих внутренних объектов, но он не гарантированно безопасен, если исключение выходит за его пределы. Поймать это исключение также небезопасно: если исключение возникло из API-интерфейса sol3, вы должны предположить, что виртуальная машина находится в неопределенном и / или сбитом состоянии.
4672
4673Пожалуйста , прочтите страницу ошибки и страницу исключения для получения более подробной информации о том , что делать с исключениями , которые взрываются из API.
4674
4675функции и передача аргументов
4676Все аргументы переданы. В отличие от get / set / operator [] для sol :: state или sol :: table , семантика значений здесь не используется. Это пересылка эталонной семантики, которая не копирует / не перемещает, если это не сделано специально для принимающих функций / специально для пользователя.
4677
4678Заметка
4679
4680Это также означает, что вы должны передавать и получать аргументы определенными способами, чтобы максимизировать эффективность. Так , например, sol::table, sol::object, sol::userdataи друзья дешевы копировать, и следует просто принимать в качестве значений. Это включает в себя примитивные типы, такие как intи double. Однако типы C ++ - если вы не хотите копировать - следует использовать как или , чтобы сохранить копии, если это важно. Обратите внимание, что получение ссылок из Lua также означает, что вы можете напрямую изменять данные внутри Lua, поэтому будьте осторожны. Lua по умолчанию имеет дело с вещами в основном по ссылке (за исключением примитивных типов).const type&type&
4681
4682Когда вы связываете функцию с Lua, пожалуйста, примите любые аргументы указателя как T*, если вы точно не знаете, что будете соответствовать точному типу уникального / общего указателя и классу, который он переносит. sol3 не может поддерживать «неявное приведение обернутых указателей», например, shared_ptr<MySecondBaseClass>когда передается функция a shared_ptr<MyDerivedClass>. Иногда это может сработать, потому что компилятор может выстроить ваши классы таким образом, чтобы сработало непосредственное приведение, но это неопределенное поведение насквозь, и sol3 не имеет механизмов, с помощью которых он может сделать это безопасно и не взорваться в лицо пользователя.
4683
4684Заметка
4685
4686Пожалуйста, избегайте использования специальных аргументов unique_usertype, либо по ссылке, либо по значению. Во многих случаях по значению не работает (например, с unique_ptr), потому что многие типы только для перемещения, и Lua не имеет понятия семантики «перемещения». Ссылка на ссылку опасна, потому что sol3 передаст вам ссылку на исходные данные: но любые указатели, хранящиеся в Lua, могут быть признаны недействительными, если вы вызовете .reset()или схоже с указателем ядра. Пожалуйста, возьмите указатель ( T*), если вы ожидаете nil/ будете nullptrпереданы вашей функции, или ссылку ( илиconst T&T&) Если вы этого не сделаете. В качестве примечания: если вы пишете небольшой класс-обертку, который содержит базовый тип указателя, и взаимодействуете с помощью обертки, то, когда вы получаете обертку в качестве аргумента в C ++ -функции, связанной с Lua, вы можете свободно приводить внутренний объект. Это просто прямое приведение в качестве аргумента к функции, которая является проблемой.
4687
4688Заметка
4689
4690Вы можете получить даже больше скорости из sol::objectстиля типов путем осуществления sol::stack_object(или sol::stack_..., где ...это userdata, reference, tableи т.д.). Они ссылаются непосредственно на позицию стека, а не дешево / безопасно, на внутреннюю ссылку Lua, чтобы быть уверенным, что она не может быть выметена из-под вас. Обратите внимание, что если вы манипулируете стеком из-под этих объектов, они могут плохо себя вести, поэтому, пожалуйста, не взрывайте свой стек Lua при работе с этими типами.
4691
4692string(и wstring) являются особенными. Lua хранит строки как строки с нулевым символом в конце. будет копировать, поэтому взятие по значению или по константной ссылке все равно вызывает операцию копирования. Вы можете взять a , но это будет означать, что вы знакомы с тем, что происходит в стеке Lua (если вы измените его и начнете отбирать аргументы функций из него в вызовах функций и т. Д., О чем ранее было предупреждено).const char*stringstringconst char*
4693
4694безопасность вызова функции
4695У вас могут быть функции здесь и при проверке пользовательских типов, чтобы определенно убедиться, что типы, передаваемые в функции C ++, являются такими, какими они должны быть, добавив перед включением sol или передавая его в командной строке. В противном случае, по соображениям скорости, эти проверки используются только там, где это абсолютно необходимо (например, различение перегрузок ). Смотрите безопасность для получения дополнительной информации.#define SOL_ALL_SAFETIES_ON
4696
4697необработанные функции ( lua_CFunction)
4698Когда вы помещаете функцию в Lua, используя sol, используя любые методы, и эта функция точно соответствует сигнатуре , она будет рассматриваться как необработанная функция C (a ). Это означает, что обычный исключительный батутный соль оборачивает вызовы других ваших функций, не будет присутствовать. Вы будете нести ответственность за перехват исключений и их обработку до того, как они взорвутся в C API (и, возможно, уничтожат ваш код). Sol во всех других случаях добавляет батут для обработки исключений, который превращает исключения в ошибки Lua, которые могут быть обнаружены вышеупомянутыми защищенными функциями и средствами доступа.int( lua_State* );lua_CFunction
4699
4700Обратите внимание, что лямбды без сохранения состояния можно преобразовать в указатель на функцию, поэтому лямбды без сохранения состояния, аналогичные форме , также будут выдаваться как необработанные функции. Если вам нужно получить состояние Lua, вызывающее функцию, используйте sol :: this_state .[](lua_State*) -> int { ... }
4701
4702Предупреждение
4703
4704НЕ предполагайте, что сборка Lua как C ++ позволит вам бросать напрямую из необработанной функции. Если возбуждается исключение и оно всплывает в инфраструктуру Lua, даже если вы компилируете как C ++, Lua не распознает исключения, кроме тех, которые он использует lua_error. Другими словами, он вернет какой-то полностью ложный результат, потенциально оставит ваш стек Lua перебитым, а остальная часть вашей виртуальной машины может находиться в полуразрушенном состоянии. Пожалуйста, избегайте этого!
4705
4706« Особенности :: Содержание :: Типы пользователей »
4707
4708функция
4709вызов функций, связанных с Lua
4710
4711Заметка
4712
4713Эта абстракция предполагает, что функция работает безопасно. Если вы ожидаете, что в вашем коде есть ошибки (например, вы не всегда имеете явный контроль над ним или пытаетесь отлаживать ошибки), пожалуйста, явно используйте sol :: protected_function . Вы также можете сделать по sol::functionумолчанию sol::protected_function, включив функции безопасности .
4714
4715class unsafe_function : public reference;
4716typedef unsafe_function function;
4717Функция является верной версией защищенной функции , исключающей необходимость проверок типов и обработки ошибок (таким образом, в некоторых случаях незначительно увеличивает скорость). Это тип функции по умолчанию sol. Возьмите функцию прямо из стека, используя конструктор:
4718
4719конструктор: unsafe_function
4720unsafe_function(lua_State* L, int index = -1);
4721Вызывает конструктор и создает этот тип прямо из стека. Например:
4722
4723funcs.lua
4724 bark_power = 11;
4725
4726 function woof ( bark_energy )
4727 return (bark_energy * (bark_power / 4))
4728 end
4729Следующий код C ++ вызовет эту функцию из этого файла и получит возвращаемое значение:
4730
4731
4732#define SOL_ALL_SAFETIES_ON 1
4733#include <sol/sol.hpp>
4734
4735#include "assert.hpp"
4736
4737int main (int, char*[]) {
4738
4739 sol::state lua;
4740
4741 lua.script(code);
4742
4743 sol::function woof = lua["woof"];
4744 double numwoof = woof(20);
4745 c_assert(numwoof == 55.0);
4746Вызов woof(20)генерирует unsafe_function_result , который затем неявно преобразуется в doubleпосле вызова . Промежуточный временный function_resultобъект затем разрушается, выводя результаты вызова функции Lua из стека Lua.
4747
4748Вы также можете вернуть несколько значений с помощью tupleили, если вам нужно привязать их к существующим переменным, используйте sol::tie:
4749
4750
4751 lua.script( "function f () return 10, 11, 12 end" );
4752
4753 sol::function f = lua["f"];
4754 tuple<int, int, int> abc = f();
4755 c_assert(get<0>(abc) == 10);
4756 c_assert(get<1>(abc) == 11);
4757 c_assert(get<2>(abc) == 12);
4758 // or
4759 int a, b, c;
4760 sol::tie(a, b, c) = f();
4761 c_assert(a == 10);
4762 c_assert(b == 11);
4763 c_assert(c == 12);
4764
4765 return 0;
4766}
4767Это значительно облегчает работу с несколькими возвращаемыми значениями. Использование tieиз стандарта C ++ приведет к висящим ссылкам или плохому поведению из-за очень плохого способа, которым кортежи / C ++ tieбыли определены и реализованы: используйте вместо этого, чтобы удовлетворить любые требования множественного возврата.sol::tie( ... )
4768
4769Предупреждение
4770
4771НЕ сохраняйте возвращаемый тип unsafe_function_result ( function_resultкогда настройки безопасности не включены ) с помощью auto, как в , и НЕ храните его где-либо. В отличие от его аналога protected_function_result , хранить его НЕ безопасно, так как предполагается, что его возвращаемые типы все еще находятся на вершине стека, а при вызове деструктора выскакивает число результатов, которые функция должна была вернуть с вершины стека. Если вы возитесь со стеком Lua между сохранением и его уничтожением, вы будете подвержены невероятному количеству удивительных и трудно отслеживаемых ошибок. Не делай этого.auto numwoof = woof(20);function_resultfunction_result
4772
4773функция: оператор вызова / вызов функции
4774template<typename... Args>
4775unsafe_function_result operator()( Args&&... args );
4776
4777template<typename... Ret, typename... Args>
4778decltype(auto) call( Args&&... args );
4779
4780template<typename... Ret, typename... Args>
4781decltype(auto) operator()( types<Ret...>, Args&&... args );
4782Вызывает функцию. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Функция предполагает, что ошибок времени выполнения нет, и, таким образом, будет вызывать функцию, если обнаружится ошибка, и в противном случае может вернуть мусорные / поддельные значения, если пользователь не будет осторожен.my_func(sol::types<int, string>, ...)atpanic
4783
4784Чтобы узнать больше о том, как обрабатываются аргументы функции, см. Это примечание
4785
4786« Tie :: Contents :: protected_function »
4787
4788контейнеры
4789работа с контейнерами в sol3
4790
4791Контейнеры - это объекты, которые должны проверяться и повторяться, и задача которых обычно заключается в предоставлении хранилища для коллекции элементов. Стандартная библиотека имеет несколько контейнеров разных типов, и у всех них есть begin()и end()методы, которые возвращают итераторы. Массивы в стиле C также являются контейнерами, и sol3 обнаружит их все для использования и присвоит им специальные свойства и функции.
4792
4793Контейнеры из C ++ хранятся как userdataсо специальными usertypeметатаблицами со специальными операциями
4794В Lua 5.1 это означает, что контейнеры, помещенные без оболочек, таких как as_table и nested , не будут работать с pairsдругими встроенными итерационными функциями Lua или другими встроенными функциями
4795Lua 5.2+ будет вести себя нормально (не включает LuaJIT 2.0.x)
4796Вы должны помещать контейнеры в C ++, возвращая их напрямую и получая / устанавливая их напрямую, и они будут иметь тип sol::type::userdataи обрабатываться как пользовательский тип
4797Контейнером можно манипулировать как из C ++, так и из Lua, и, как и пользовательские данные, будут отражать изменения, если вы используете ссылку на данные.
4798Это означает, что контейнеры автоматически не сериализуются как таблицы Lua
4799Если вам нужны таблицы, рассмотрите возможность использования sol::as_tableиsol::nested
4800Смотрите этот пример сериализации таблицы для более подробной информации
4801Lua 5.1 имеет различную семантику для pairsи ipairs: будьте осторожны. Смотрите примеры ниже для более подробной информации
4802Вы можете переопределить поведение контейнера, переопределив черту обнаружения и специализировав шаблон usertype_container
4803Вы можете связать типичные массивы в стиле C, но должны следовать правилам
4804Заметка
4805
4806Обратите внимание, что массивы c-style должны быть добавлены в Lua с помощью или для передачи этих свойств. Нет, простой указатель не считается массивом. Это важно, потому что также типизируется как array ( ), и, таким образом, мы можем использовать s или указатели на фактические типы массивов, чтобы работать для этой цели.lua["my_arr"] = &my_c_array;lua["my_arr"] = ref(my_c_array);T*lua["my_string"] = "some string";const char[n]reference_wrapper
4807
4808обнаружение контейнера
4809Контейнеры обнаруживаются по типу признака sol::is_container<T>. Если это окажется правдой, sol3 попытается отправить пользовательские данные в Lua для указанного типа Tи наделить их некоторыми функциями и свойствами, перечисленными ниже. Эти функции и свойства обеспечиваются шаблонной структурой sol::usertype_container<T>, в которой есть ряд статических функций Lua C, связанных с метастабильностью безопасности. Если вы хотите переопределить поведение для конкретного контейнера, вы должны сначала специализироваться sol::is_container<T>для извлечения true_type, а затем переопределить функции, которые вы хотите изменить. Любая функция, которую вы не переопределите, будет вызывать реализацию по умолчанию или эквивалентную ей. Реализация по умолчанию для нераспознанных контейнеров - просто ошибки.
4810
4811Вы также можете специализироваться на том, sol::is_container<T>чтобы отключить обнаружение контейнера, если вы находите его слишком нетерпеливым для типа, который, как оказалось, имеет функции beginи endфункционирует, например, так:
4812
4813not_container.hpp
4814struct not_container {
4815 void begin() {
4816
4817 }
4818
4819 void end() {
4820
4821 }
4822};
4823
4824namespace sol {
4825 template <>
4826 struct is_container<not_container> : false_type {};
4827}
4828Это позволит типу выдвигаться как обычные данные пользователя.
4829
4830Заметка
4831
4832Нажатие на новый тип пользователя предотвратит обработку соответствующего типа контейнера C ++ как контейнера. Чтобы заставить тип, который вы зарегистрировали / связали как тип пользователя, используя new_usertypeили new_simple_usertypeобрабатывать как контейнер, используйте sol :: as_container .
4833
4834переопределение контейнера
4835Если вы хотите , чтобы это участие в качестве таблицы, используйте true_typeвместо false_typeот обнаружения containter примера. и предоставить соответствующие iteratorи value_typeопределения типа. Невыполнение этого требования приведет к контейнеру, чьи операции по умолчанию завершаются неудачно (или компиляция завершится неудачей).
4836
4837Если вам нужен тип, объявление и определение которого вы не можете контролировать как контейнер, то вы должны переопределить поведение по умолчанию, специализируя свойства контейнера, например:
4838
4839specializing.hpp
4840struct not_my_type { ... };
4841
4842namespace sol {
4843 template <>
4844 struct is_container<not_my_type> : true_type {};
4845
4846 template <>
4847 struct usertype_container<not_my_type> {
4848
4849 ...
4850 // see below for implemetation details
4851 };
4852}
4853Предполагается, что различные операции, представленные ниже usertype_container<T>, будут такими. Возможность их переопределения требует знания стека Lua и того, как он работает, а также знания необработанных C-функций Lua . Вы можете прочитать о сырых функциях Си, взглянув на книгу «Программирование на Lua». Информация онлайн-версии о стеке и о том, как вернуть информацию, по-прежнему актуальна, и вы можете комбинировать ее, используя также низкоуровневый API стека sol для достижения желаемого поведения.
4854
4855Предупреждение
4856
4857Обработка исключений БУДЕТ быть предусмотрена вокруг этих конкретных исходных функций C, так что вам не нужно беспокоиться об исключениях или ошибках кипящих до конца и обработок этой части. Это специально обрабатывается для вас в этом конкретном случае, и ТОЛЬКО в этом конкретном случае. Необработанная заметка по-прежнему применяется ко всем другим необработанным функциям C, которые вы делаете вручную.
4858
4859контейнерные операции
4860Ниже приведены многие контейнерные операции и их точки переопределения для usertype_container<T>. Пожалуйста, используйте их, чтобы понять, как использовать любую часть реализации.
4861
4862операция синтаксис lua usertype_container <T> точка расширения порядок аргументов стека Заметки / предостережения
4863задавать c:set(key, value) static int set(lua_State*); 1 self 2 key 3 value
4864Если valueэто ноль, он выполняет стирание в реализации по умолчанию
4865если это контейнер, который поддерживает вставку и `` ключ`` является индексом, равным (размер контейнера) + 1, он вставит значение в конец контейнера (это идиома Lua)
4866реализация по умолчанию использует .insertили оператор [] для массивов c
4867index_set c[key] = value static int index_set(lua_State*); 1 self 2 key 3 value
4868реализация по умолчанию откладывает работу на «set»
4869если это контейнер последовательности и он поддерживает вставку и keyявляется индексом, равным размеру контейнера +1, он будет вставлен в конец контейнера (это идиома Lua)
4870в v = c:at(key) static int at(lua_State*); 1 self 2 index
4871может вернуть несколько значений
4872реализация по умолчанию увеличивает итераторы линейно для не случайного доступа; использует, .find()если доступно
4873если тип не имеет итераторов с произвольным доступом, не используйте это в цикле for !
4874получить v = c:get(key) static int get(lua_State*); 1 сам 2 ключа
4875может вернуть несколько значений
4876реализация по умолчанию увеличивает итераторы линейно для не случайного доступа
4877index_get v = c[key] static int index_get(lua_State*); 1 сам 2 ключа
4878может вернуть только 1 значение
4879реализация по умолчанию откладывает работу, чтобы "получить"
4880Если keyэто строка и keyявляется одной из других функций-членов, она вернет эту функцию, а не выполнит поиск / индекс
4881находить c:find(target) static int find(lua_State*); 1 само 2 цель
4882target значение для контейнеров без поиска (фиксированные контейнеры, контейнеры последовательностей, неассоциативные и неупорядоченные контейнеры)
4883стирать c:erase(target) static int erase(lua_State*); 1 само 2 цель
4884для контейнеров последовательности, targetэто индекс для удаления
4885для контейнеров поиска, targetявляется типом ключа
4886использует линейное приращение , чтобы место для контейнеров последовательности , которые не имеют случайные итераторы доступа ( list, forward_listи тому подобные)
4887может сделать недействительной итерацию
4888вставить c:insert(target, value) 1 self 2 target 3 key
4889для контейнеров последовательности target- это индекс, в противном случае это тип ключа
4890вставляет в контейнер по возможности в указанном месте
4891добавлять c:add(key, value) или же c:add(value) static int add(lua_State*); 1 self 2 key / value 3 value
48922-й аргумент (3-й в стеке) предоставляется для добавления ассоциативных контейнеров
4893заказанные контейнеры будут вставлены в соответствующее место, не обязательно в конце (использует .insert(...)или .find(...)с назначением
4894может лишить законной силы итерацию
4895размер #c static int size(lua_State*); 1 себя
4896вызовы реализации по умолчанию, .size()если присутствуют
4897в противном случае реализация по умолчанию использует distance(begin(L, self), end(L, self))
4898Чисто c:clear() static int clear(lua_State*); 1 себя
4899реализация по умолчанию не обеспечивает отступления, если нет clearоперации
4900смещение н / static int index_adjustment(lua_State*, T&); н /
4901возвращает индекс, который добавляет к переданному числовому индексу для доступа к массиву (реализация по умолчанию - моделирование индексации на основе 1 из Lua)return -1
4902начать н / static iterator begin(lua_State*, T&); н /
4903вызывается по умолчанию реализация в вышеуказанных функциях
4904не является обычной необработанной функцией: должен возвращать итератор из второго аргумента «T &», который является self
4905конец н / static iterator end(lua_State*, T&); н /
4906вызывается по умолчанию реализация в вышеуказанных функциях
4907не является обычной необработанной функцией: должен возвращать итератор из второго аргумента «T &», который является self
4908следующий static int next(lua_State*); 1 себя
4909реализовать только для опытных пользователей, которые понимают предостережения по написанию nextфункции для обхода Lua
4910используется как 'итерационная функция', отправляемая с вызовом pair ()
4911пары static int pairs(lua_State*); 1 себя
4912внедрить, если продвинутый пользователь только то, что понимает предостережения
4913Вместо этого переопределите начало и конец и оставьте это для реализации по умолчанию, если вы не знаете, для чего __pairsили как реализовать это и nextфункцию
4914работает только в Lua 5.2+
4915вызов в Lua 5.1 / LuaJIT завершится с ошибкой подтверждения (Lua ожидает быть таблицей); может использоваться как обычная функция, чтобы обойти ограничениеpairs( c )cc:pairs()
4916ipairs static int ipairs(lua_State*); 1 себя
4917внедрить, если продвинутый пользователь только то, что понимает предостережения
4918Вместо этого переопределите начало и конец и оставьте это для реализации по умолчанию, если вы не знаете, для чего __ipairsили как реализовать это и nextфункцию
4919работает только в Lua 5.2, устарел в Lua 5.3 (но все еще может вызываться в режимах совместимости)
4920вызов в Lua 5.1 / LuaJIT завершится с ошибкой подтверждения (Lua ожидает быть таблицей)ipairs( c )c
4921Заметка
4922
4923Если ваш тип не адекватная поддержки begin()и , end()и вы не можете изменить его, используйте sol::is_containerчерт переопределение вместе с пользовательской реализацией pairsна вашем UserType , чтобы заставить его работать , как вы хотите. Обратите внимание, что тип не имеет надлежащего типа begin()и end()не будет работать, если вы попытаетесь принудительно сериализовать его как таблицу (это означает, что следует избегать использования sol :: as_table и sol :: nested , в противном случае у вас будут ошибки компилятора). Просто установите его или получите напрямую, как показано в примерах, для работы с контейнерами C ++.
4924
4925Заметка
4926
4927Переопределение признаков обнаружения и рабочих характеристик, перечисленных выше, а затем попытка использовать sol::as_tableили подобное может привести к сбоям компиляции, если у вас нет свойства begin()или end()функции для типа. Если вы хотите, чтобы все происходило с особыми соображениями типа пользователя, не заключайте контейнер в одну из специальных абстракций преобразования / преобразования таблиц.
4928
4929контейнерные классификации
4930Когда вы сериализуете контейнер в sol3, обработчик контейнера по умолчанию работает с контейнерами, проверяя их различные свойства, функции и определения типов. Вот общие значения контейнеров, которые по умолчанию распознает sol3, и какие уже известные контейнеры попадают в их категории:
4931
4932тип контейнера требования известные контейнеры Заметки / предостережения
4933последовательность erase(iterator) push_back/insert(value_type) std :: vector std :: deque std :: list std :: forward_list
4934find операция линейна по размеру списка (ищет все элементы)
4935std :: forward_list имеет итераторы только для пересылки: set / find является линейной операцией
4936std :: forward_list использует идиому «insert_after», требует специальной внутренней обработки
4937фиксированный не хватает push_back/ insert не хватаетerase std :: array <T, n> T [n] (фиксированные массивы)
4938обычные массивы в стиле c должны быть установлены или использоватьсяref( arr )&arr
4939C ++ реализация вставляет с помощью оператора []
4940приказал key_type ЬурейеЕ erase(key) find(key) insert(key) std :: set std :: multi_set
4941container[key] = stuffоперация стирает, когда stuffноль, вставляет / устанавливает, когда нет
4942container.get(key) возвращает сам ключ
4943ассоциативный, упорядоченный key_type, mapped_typetypedefs erase(key) find(key) insert({ key, value }) std :: map std :: multi_map
4944неупорядоченный так же, как приказано std :: unordered_set std :: unordered_multiset
4945container[key] = stuffоперация стирает, когда stuffноль, вставляет / устанавливает, когда нет
4946container.get(key) возвращает сам ключ
4947итерация не гарантируется в порядке вставки, как в контейнере C ++
4948неупорядоченный, ассоциативный так же, как приказано, ассоциативный std :: unordered_map std :: unordered_multimap
4949итерация не гарантируется в порядке вставки, как в контейнере C ++
4950полный пример
4951Вот полный рабочий пример того, как это работает для Lua 5.3 и Lua 5.2, и как вы можете извлечь контейнер во всех версиях:
4952
4953#define SOL_ALL_SAFETIES_ON 1
4954#include <sol/sol.hpp>
4955
4956#include <vector>
4957#include <iostream>
4958
4959int main(int, char**) {
4960 cout << "=== containers ===" << endl;
4961
4962 sol::state lua;
4963 lua.open_libraries();
4964
4965 lua.script(R"(
4966function f (x)
4967 print("container has:")
4968 for k=1,#x do
4969 v = x[k]
4970 print("\t", k, v)
4971 end
4972 print()
4973end
4974 )");
4975
4976 // Have the function we
4977 // just defined in Lua
4978 sol::function f = lua["f"];
4979
4980 // Set a global variable called
4981 // "arr" to be a vector of 5 lements
4982 lua["arr"] = vector<int>{ 2, 4, 6, 8, 10 };
4983
4984 // Call it, see 5 elements
4985 // printed out
4986 f(lua["arr"]);
4987
4988 // Mess with it in C++
4989 // Containers are stored as userdata, unless you
4990 // use `sol::as_table()` and `sol::as_table_t`.
4991 vector<int>& reference_to_arr = lua["arr"];
4992 reference_to_arr.push_back(12);
4993
4994 // Call it, see *6* elements
4995 // printed out
4996 f(lua["arr"]);
4997
4998 lua.script(R"(
4999arr:add(28)
5000 )");
5001
5002 // Call it, see *7* elements
5003 // printed out
5004 f(lua["arr"]);
5005
5006 lua.script(R"(
5007arr:clear()
5008 )");
5009
5010 // Now it's empty
5011 f(lua["arr"]);
5012
5013 cout << endl;
5014
5015 return 0;
5016}
5017Обратите внимание, что это не будет хорошо работать в Lua 5.1, так как он имеет явные проверки таблиц и не проверяет метаметоды, даже когда pairsили ipairsпередается таблица. В этом случае вам нужно будет использовать более ручную схему итерации или вам придется преобразовать ее в таблицу. В C ++ можно использовать золь :: as_table при прохождении что - то в библиотеку , чтобы получить таблицу из него: . Для ручной итерации в коде Lua без использования чего-либо с индексами попробуйте:lua["arr"] = as_table( vector<int>{ ... });as_table
5018
5019iteration.lua
50201
50212
50223
5023for i = 1, #vec do
5024 print(i, vec[i])
5025end
5026Есть и другие способы перебора ключей / значений, но они могут быть трудными и снижать производительность из-за отсутствия надлежащей поддержки в Lua 5.1. Мы рекомендуем вам перейти на Lua 5.2 или 5.3, если это является неотъемлемой частью вашей инфраструктуры.
5027
5028Если вы не можете my_container:pairs()выполнить обновление, используйте функцию «member» в Lua для выполнения итерации:
5029
5030
5031#define SOL_ALL_SAFETIES_ON 1
5032#include <sol/sol.hpp>
5033
5034#include "assert.hpp"
5035
5036#include <unordered_set>
5037#include <iostream>
5038
5039int main() {
5040 struct hasher {
5041 typedef pair<string, string> argument_type;
5042 typedef size_t result_type;
5043
5044 result_type operator()(const argument_type& p) const {
5045 return hash<string>()(p.first);
5046 }
5047 };
5048
5049 using my_set = unordered_set<pair<string, string>, hasher>;
5050
5051 cout << "=== containers with pair<> ===" << endl;
5052
5053 sol::state lua;
5054 lua.open_libraries(sol::lib::base);
5055
5056 lua.set_function("f", []() {
5057 return my_set{ { "key1", "value1" },{ "key2", "value2" },{ "key3", "value3" } };
5058 });
5059
5060 lua.safe_script("v = f()");
5061 lua.safe_script("print('v:', v)");
5062 lua.safe_script("print('#v:', #v)");
5063 // note that using my_obj:pairs() is a
5064 // way around pairs(my_obj) not working in Lua 5.1/LuaJIT: try it!
5065 lua.safe_script("for k,v1,v2 in v:pairs() do print(k, v1, v2) end");
5066
5067 cout << endl;
5068
5069 return 0;
5070}
5071« Usertypes :: Contents :: threading »
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082типы пользователей
5083Возможно, наиболее мощная функция sol3 usertypes- это способ, с помощью которого sol3 и C ++ связывают ваши классы со средой исполнения Lua и связывают вещи между обеими таблицами и конкретными блоками памяти C ++, позволяя обрабатывать пользовательские данные Lua и другие вещи, такие как классы.
5084Чтобы узнать больше о пользовательских типах, посетите:
5085основной учебник
5086учебник по настройке
5087API документация
5088документация памяти
5089В папке примеров также есть несколько действительно хороших примеров для просмотра. Ниже также приведены некоторые примечания о гарантиях, которые вы можете найти о пользовательских типах и связанных с ними пользовательских данных:
5090Контейнеры выдвигаются как специальные пользовательские типы, но могут быть отключены, если возникают проблемы, как подробно описано здесь .
5091Определенные операторы обнаруживаются и автоматически связываются для пользовательских типов
5092Вы можете использовать битовые поля, но это требует некоторой утонченности с вашей стороны. У нас есть пример, чтобы помочь вам начать здесь, который использует несколько хитростей .
5093Все типы пользователей расширяются во время выполнения как в Lua, так и в C ++
5094Если вам нужны динамические обратные вызовы или переопределяемые во время выполнения функции, используйте functionпеременную-член и получите / установите ее для объекта usertype
5095functionработает как переменная-член или при передаче в качестве аргумента / возвращает значение (вы даже можете использовать его с sol::property)
5096Вы также можете создать полностью динамический объект: см. Пример dynamic_object для более подробной информации.
5097Вы можете использовать политики, чтобы управлять зависимостями и оптимизировать возвращаемые значения, а также применять настраиваемое поведение к возвращаемым функциям.
5098Вы можете работать со специальными типами оболочек , таких как unique_ptr<T>, shared_ptr<T>и другие по умолчанию
5099Расширьте их, используя черты sol :: unique_usertype <T>
5100Это позволяет настраиваемым интеллектуальным указателям, специальным указателям, настраиваемым дескрипторам и другим указывать определенную семантику обработки для обеспечения надлежащего RAII с помощью сборки мусора Lua
5101(Дополнительно) Вы можете переопределить функцию итерации для Lua 5.2 и выше (LuaJIT не имеет возможности), как показано в примере пар
5102(Advanced) Interop с toLua, kaguya, OOLua, LuaBind, luwra, и всеми другими существующими библиотеками по использованию стека API по sol::stack::userdata_checkerи sol::stack::userdata_getter точке расширения
5103Необходимо включить SOL_ENABLE_INTEROP, как определено в документации по конфигурации и безопасности , чтобы использовать
5104Вот несколько других общих советов и советов для понимания и работы с типами пользователей:
5105Обратите внимание, что двоеточие необходимо для «автоматической» передачи аргумента this/ selfв методы Lua
5106obj:method_name() как вы называете «член» методы в Lua
5107Это чисто синтаксический сахар, который передает имя объекта в качестве первого аргумента method_nameфункции
5108my_obj:foo(bar, baz) такой же как my_obj.foo(my_obj, bar, baz)
5109Обратите внимание, что один использует двоеточие, а другой использует точку, и если вы забудете сделать это правильно, ваш код будет зависать
5110Есть определения безопасности, изложенные на странице безопасности здесь
5111Вы можете нажать типы, классифицированные как userdata, прежде чем зарегистрировать usertype.
5112Вы можете в любое время зарегистрировать тип пользователя в среде исполнения Lua.
5113Вы можете получить пользовательский тип из среды выполнения Lua в любое время.
5114Методы и свойства будут добавлены к типу только после регистрации пользовательского типа во время выполнения Lua
5115Все методы и свойства будут отображаться во всех пользовательских данных, даже если этот объект был передан перед пользовательским типом (все пользовательские данные будут обновлены).
5116Типы либо копируют один раз, либо перемещают один раз в область памяти, если это тип значения. Если это указатель, мы храним только ссылку
5117Это означает получение типов классов (не примитивных типов, таких как строки или целые числа), T&или T*позволяет вам изменять данные в Lua напрямую
5118Получить равнину, Tчтобы получить копию
5119Типы возврата и передачи аргументов sol::function-типам используют идеальную семантику пересылки и ссылки, что означает, что копирование не происходит, если вы не укажете значение явно. Смотрите это примечание для деталей
5120Вы можете установить indexи new_indexсвободно использовать любой пользовательский тип, который хотите переопределить, по умолчанию «если ключ отсутствует, найти его / установить его здесь» функциональность определенного объекта пользовательского типа.
5121new_indexи indexне будет вызван, если вы попытаетесь манипулировать именованной таблицей пользовательских типов напрямую. Sol3 будут вызваны для добавления этой функции в таблицу поиска функций / переменных пользовательского типа.
5122new_indexи indexбудет вызываться, если вы попытаетесь вызвать ключ, который не существует в самом объекте пользовательских данных (объект C ++)
5123Если вы создали тип пользователя с именем test, это означает , что с вызовет вашу функцию, но вместо этого установит ключ для поиска этой функции для всех типов.t = test()t.hi = 54test.hi = function () print ("hi"); endhitest
5124Первые байты всегда указатель на типизированную память C ++. То, что происходит после, зависит от того, что вы вставили в систему в соответствии со спецификацией памяти для пользовательских типов . Это совместимо с рядом систем, отличных от sol3, что упрощает взаимодействие с другими системами Lua.sizeof( void* )
5125Методы, свойства, переменные и функции-члены, принимающие self&аргументы, изменяют данные напрямую
5126Работайте над копией, принимая аргументы или возвращая по значению.
5127Не используйте ссылки на r-значения: они ничего не значат в коде Lua.
5128Типы только для перемещения могут быть взяты только по ссылке: sol3 не может знать, если / когда перемещать значение (кроме случаев, когда сериализация выполняется с идеальной пересылкой в Lua, но не вызывает функцию C ++ из Lua)
5129Фактическая метатабель, связанная с типом пользователя, имеет длинное имя и определена как непрозрачная реализацией sol.
5130Фактическая метатабельная внутренняя работа непрозрачна и определяется реализацией sol, и внутренних документов нет, поскольку оптимизация операций применяется на основе эвристики, которую мы обнаруживаем при тестировании производительности системы.
5131« Функции ::
5132тип пользователя <T> ¶
5133структуры и классы из C ++, доступные для кода Lua
5134
5135Заметка
5136
5137T относится к типу, превращаемому в тип пользователя.
5138
5139class metatable : public table;
5140
5141template <typename T>
5142class usertype : public metatable;
5143В то время как другие платформы расширяют синтаксис lua или создают языки структуры данных (DSL) для создания классов в Lua, sol вместо этого предлагает возможность генерировать легкие привязки, которые снижают производительность. Вы можете увидеть небольшой стартовый пример здесь . Они используют метатаблицы и пользовательские данные в Lua для их реализации. Типы пользователей также могут быть расширены во время выполнения .
5144
5145Существуют более сложные варианты использования для создания и использования пользовательского типа, которые основаны на том, как использовать функцию .set () и ее первоначальную конструкцию (см. Ниже).
5146
5147перечисления
5148перечисление meta_function для имен
5149
5150enum class meta_function {
5151 construct,
5152 index,
5153 new_index,
5154 mode,
5155 call,
5156 call_function = call,
5157 metatable,
5158 to_string,
5159 length,
5160 unary_minus,
5161 addition,
5162 subtraction,
5163 multiplication,
5164 division,
5165 modulus,
5166 power_of,
5167 involution = power_of,
5168 concatenation,
5169 equal_to,
5170 less_than,
5171 less_than_or_equal_to,
5172 garbage_collect,
5173 floor_division,
5174 bitwise_left_shift,
5175 bitwise_right_shift,
5176 bitwise_not,
5177 bitwise_and,
5178 bitwise_or,
5179 bitwise_xor,
5180 pairs,
5181 ipairs,
5182 next,
5183 type,
5184 type_info,
5185 call_construct,
5186 storage,
5187 gc_names,
5188 static_index,
5189 static_new_index,
5190};
5191
5192typedef meta_function meta_method;
5193Используйте это перечисление, чтобы указать имена более удобным способом, чем запоминание специальных имен мета-методов lua для каждого из них. Каждый связывается с определенной операцией, обозначенной описательным именем перечисления. Вы можете прочитать больше о метаметодах в руководстве Lua и узнать о том, как они работают и, как предполагается, будут реализованы там. Каждое из имен здесь (за исключением тех, которые используются в качестве ярлыков для других имен, таких как, meta_function::call_functionно meta_function::involutionне включая construct, которые просто отображаются на имя new), напрямую связаны с именем Lua для операции. meta_function::pairsдоступно только в Lua 5.2 и выше (не включает LuaJIT или Lua 5.1) и meta_function::ipairsдоступно только в Lua 5.2 (без учета флагов совместимости).
5194
5195Некоторые из них также sol2 конкретных, например meta_function::type_info, meta_function::call_construct, meta_function::static_indexи meta_function::static_new_indexявляются sol2 конкретными и полезными для пользователей. Записи meta_function::storageи meta_function::gc_namesявляются sol2-внутренними, но все еще в перечислении; пожалуйста , не используйте их.
5196
5197meta_function::indexи meta_function::new_indexприменяется строго к тому, когда объект в Lua вызывается с ключом, которого он еще не знает (например, он не был связан программистом C ++ с помощью .set(...)или .new_usertype<...>(...);. meta_function::static_indexи функции meta_function :: static_new_index` вызываются, когда ключ не найден и Пользователь вызывает новую функцию из названной метатаблицы.
5198
5199структуры
5200automagic_enrollments для специальных членов, определенных в классе
5201 1
5202 2
5203 3
5204 4
5205 5
5206 6
5207 7
5208 8
5209 9
521010
521111
5212struct automagic_enrollments {
5213 bool default_constructor = true;
5214 bool destructor = true;
5215 bool pairs_operator = true;
5216 bool to_string_operator = true;
5217 bool call_operator = true;
5218 bool less_than_operator = true;
5219 bool less_than_or_equal_to_operator = true;
5220 bool length_operator = true;
5221 bool equal_to_operator = true;
5222};
5223Эта структура используется new_usertypeдля специального назначения определенных специальных функций-членов, связанных с Lua, независимо от того, способна ли она на них или нет.
5224
5225new_usertype / set
5226sol::usertype<T>это специализированная версия . требует, чтобы тип пользователя был определенным метатабельным для определенного класса. Оба они являются производными типами sol :: reference <reference> , то есть они принимают в . Например…sol::metatable``s, which are a specialized version of ``sol::tablesol::metatable``s attempt to treat the table like either a Lua or a sol2 metatable. ``sol::usertype<T>lua_State*
5227
5228new_usertype / set options
5229Если типом является default_constructible , sol сгенерирует "new"член для типа пользователя для вас. В противном случае используйте для предотвращения конструктора или передайте при вызове . В противном случае ниже приведены специальные способы обработки конструкции пользовательского типа:my_table.new_usertype<MyType>("name", sol::no_constructor);sol::automagic_enrollments enrollments; /* modify members here */;.new_usertype<MyType>("name", enrollments);
5230
5231"{name}", constructors<T(), T(arg-1-0), T(arg-2-0, arg-2-1), ...>
5232Укажите конструкторы, которые будут связаны в nameсписке конструкторов, указав их сигнатуру функции сclass_type(arg0, arg1, ... argN)
5233Если вы передаете constructors<...>аргумент первый при построении UserType, то он автоматически будет дан "{name}"из"new"
5234"{name}", constructors<Type-List-0, Type-List-1, ...>
5235Этот синтаксис длиннее и предоставляется для обратной совместимости: приведенный выше синтаксис аргумента короче и чище
5236Type-List-Nдолжен быть sol::types<Args...>, где Args...список типов, которые принимает конструктор. Поддерживает перегрузку по умолчанию
5237Если вы передаете constructors<...>аргумент первый при построении UserType, то он автоматически будет дан "{name}"из"new"
5238"{name}", sol::initializers( func1, func2, ... )
5239Используется для обработки функций инициализатора, которые должны инициализировать саму память (но на самом деле не выделяют память, поскольку это поступает как блок пользовательских данных из Lua)
5240Предоставляется одна или несколько функций, предоставляет перегруженную функцию Lua для создания указанного типа.
5241Функция должна иметь сигнатуру аргумента или , где указатель или ссылка будут указывать на место выделенной памяти, которое неинициализировано . Обратите внимание, что Lua управляет памятью, поэтому выполнение а и установка его на или является плохой идеей: вместо этого используйте для вызова конструктора или работайте с памятью точно так, как считаете нужнымfunc( T*, Arguments... )func( T&, Arguments... )TnewT*T&placement new
5242{anything}, sol::factories( func1, func2, ... )
5243Используется для указания того, что функция завода (например, то , что производит , , или подобное) будет создавать тип объектаunique_ptr<T, ...>shared_ptr<T>T
5244Предоставляется одна или несколько функций, предоставляет перегруженную функцию для вызова
5245Функции могут принимать любую форму и возвращать что угодно, поскольку они просто считаются какой-то простой функцией и не требуют нового размещения или иного выполнения. Результаты этой функции будут добавлены в Lua по тем же правилам, что и все остальные.
5246Может использоваться для остановки генерации конструктора по .new()умолчанию, поскольку sol::factoriesзапись будет распознаваться как конструктор для пользовательского типа
5247Если этого недостаточно, посмотрите следующие 2 записи о том, как конкретно заблокировать конструктор
5248{anything}, {some_factory_function}
5249По сути, связывает то, что функция должна называть {anything}
5250При использовании С sol::no_constructorопцией ниже (например, и после этого ) можно удалить типичные пути конструктора и затем предоставить только определенные фабричные функции. Обратите внимание, что эта комбинация похожа на использование метода, упомянутого ранее в этом списке. Чтобы контролировать деструктор, смотрите далее ниже"new", sol::no_constructor"create", &my_creation_funcsol::factories
5251sol::call_constructor, {valid constructor / initializer / factory}
5252Цель этого состоит в том, чтобы включить синтаксис и вызвать этот конструктор; у него нет другой целиlocal v = my_class( 24 )
5253Это совместимо с luabind, kaguya и другими синтаксисами библиотеки Lua и выглядит аналогично синтаксису C ++, но общее согласие в программировании на Lua и других местах заключается в использовании функции с именем new
5254Обратите внимание, что с sol::call_constructorключом должен быть указан тип конструкции выше. Свободная функция без нее передаст метатаблицу, описывающую этот объект как первый аргумент без этого различия, что может вызвать странные ошибки во время выполнения.
5255{anything}, sol::no_constructor
5256В частности, говорит Sol не создавать, .new()если один не указан, и тип является конструируемым по умолчанию
5257Когда ключ {anything}вызывается на столе, это приведет к ошибке. Ошибка может быть в том, что тип неконструктивен.
5258Используйте это плюс некоторые из вышеперечисленных, чтобы разрешить функцию фабрики для вашего типа функции, но запретить другие типы идиом конструктора в Lua
5259{anything}, sol::no_constructor
5260В частности, говорит Sol не создавать, .new()если один не указан, и тип является конструируемым по умолчанию
5261Когда ключ {anything}вызывается на столе, это приведет к ошибке. Ошибка может быть в том, что тип неконструктивен.
5262Используйте это плюс некоторые из вышеперечисленных, чтобы разрешить функцию фабрики для вашего типа функции, но запретить другие типы идиом конструктора в Lua
5263параметры деструктора типа пользователя
5264Если вы вообще ничего не указали и тип является разрушаемым , то деструктор будет привязан к метаметоду сбора мусора. В противном случае ниже приведены специальные способы обработки уничтожения пользовательского типа:
5265
5266"__gc", sol::destructor( func ) или же sol::meta_function::garbage_collect, sol::destructor( func )
5267Создает пользовательский деструктор, который принимает аргумент T*или T&и ожидает, что он будет уничтожен / уничтожен. Обратите внимание, что lua контролирует память и, таким образом, освобождает необходимое пространство ПОСЛЕ того, как возвращается эта функция (например, не вызывайте, deleteпоскольку это попытается освободить память, которую вы не делали new)
5268Если вы просто хотите использовать конструктор по умолчанию, вы можете заменить второй аргумент на sol::default_destructor
5269Пользовательский тип выдаст ошибку / throw, если вы укажете деструктор, но не отобразите его sol::meta_function::gcили строку, эквивалентную"__gc"
5270Заметка
5271
5272Вы ДОЛЖНЫ указать sol::destructorвокруг своей функции уничтожения, иначе она будет проигнорирована.
5273
5274пользовательские автоматические (автоматические) мета-функции
5275Если вы не укажете sol::meta_functionимя (или эквивалентное имя Tметаметода строки) и этот тип поддерживает определенные операции, sol3 сгенерирует следующие операции, если сможет найти хорошую реализацию по умолчанию:
5276
5277для to_stringопераций, где , или (в пространстве имен) существует тип C ++ostream& operator<<( ostream&, const T& )obj.to_string()to_string( const T& )
5278sol::meta_function::to_stringоператор будет создан
5279запись делается либо
5280ostringstreamдо базовой строки сериализации в Lua
5281непосредственно сериализует возвращаемое значение obj.to_string()илиto_string( const T& )
5282порядок предпочтений: затем функция-член , затем ADL-поиск на основеostream& operator<<obj.to_string()to_string( const T& )
5283если вам нужно отключить это поведение для типа (например, чтобы избежать ошибок компилятора при конфликтах ADL), специализируйте sol::is_to_stringable<T>для своего типа false_type, например:
5284namespace sol {
5285 template <>
5286 struct is_to_stringable<my_type> : false_type {};
5287}
5288для операций вызова, где существует тип C ++operator()( parameters ... )
5289sol::meta_function::callоператор будет создан
5290оператор вызова функции в C ++ не должен быть перегружен, иначе sol не сможет связать его автоматически
5291оператор вызова функции в C ++ не должен быть шаблонным, иначе sol не сможет связать его автоматически
5292если он перегружен или настроен, это ваша ответственность, чтобы связать его правильно
5293для автоматической итерации, где begin()и end()существуют на типе C ++
5294sol::meta_function::pairsоператор генерируется для вас
5295Позволяет вам повторять использование в Luafor k, v in pairs( obj ) do ... end
5296Lua 5.2 и только лучше: LuaJIT не позволяет этого, Lua 5.1 НЕ позволяет этого
5297для случаев, когда .size()существует тип C ++
5298оператор длины оператора Lua ( #my_obj) создан для вас
5299для операций сравнения, где и существуют на типе C ++operator <operator <=
5300Эти два sol::meta_function::less_than(_or_equal_to)созданы для вас
5301>и >=операторы генерируются в Lua на основе <и <=операторов
5302за operator==
5303Оператор равенства всегда будет генерироваться, делая сравнение указателей, если operator==для двух типов значений не поддерживается, или делая сравнение ссылок и сравнение значений, если operator==поддерживается
5304гетерогенные операторы не могут поддерживаться на равенство, так как Lua специально проверяет, используют ли они одну и ту же функцию для сравнения: если нет, то метод равенства не вызывается; Один из способов обойти это - написать один , вытащить аргументы 1 и 2 из стека для вашего типа, проверить все типы и затем вызвать себя после получения типов из Lua (возможно, используя sol :: stack :: get и sol :: stack :: check_get )int super_equality_function(lua_State* L) { ... }operator==
5305пользовательские стандартные функции
5306В противном случае, следующее используется для указания функций, для которых выполняется привязка к конкретному типу пользователя T.
5307
5308"{name}", &free_function
5309Привязывает свободную функцию / функцию статического класса / объект функции (лямбда) к "{name}". Если первым аргументом является T*или T&, то он будет связывать его как функцию-член. Если это не так, он будет связан как «статическая» функция в таблице lua.
5310"{name}", &type::function_name или же "{name}", &type::member_variable
5311Связывает типичную функцию-член или переменную с "{name}". В случае переменной-члена или функции-члена typeдолжно быть Tили основаниеT
5312"{name}", sol::readonly( &type::member_variable )
5313Связывает типичную переменную с "{name}". Аналогично приведенному выше, но переменная будет доступна только для чтения, то есть будет сгенерирована ошибка, если что-либо попытается записать в эту переменную
5314"{name}", sol::as_function( &type::member_variable )
5315Связывает типичную переменную с, "{name}" но заставляет синтаксис вызываться как функция . Это производит геттер и сеттер, доступные obj:name()для получения и obj:name(value)установки.
5316"{name}", sol::property( getter_func, setter_func )
5317Связывает типичную переменную с "{name}", но получает и устанавливает с использованием указанных функций set и getter. Не то, чтобы, если вы не передадите функцию установки, переменная будет доступна только для чтения. Также не то, что если вы не передадите функцию получения, она будет только для записи
5318"{name}", sol::var( some_value ) или же "{name}", sol::var( ref( some_value ) )
5319Связывает типичную переменную "{name}", необязательно по ссылке (например, ссылается на ту же память в C ++). Это полезно для глобальных переменных / статических переменных класса и т.п.
5320"{name}", sol::overload( Func1, Func2, ... )
5321Создает функцию-член oveloaded, которая различает количество аргументов и типов
5322Выгрузка нескольких функций с одним и тем же именем не создает перегрузки : вы должны использовать этот синтаксис, чтобы он работал
5323sol::base_classes, sol::bases<Bases...>
5324Сообщает типу пользователя, каковы его базовые классы. Это необходимо для правильной работы преобразований из базы в базу. См наследство
5325 регистрацию
5326Вы можете разъединить и убить UserType и связанную с ним функциональность, позвонив .unregister()на sol::usertype<T>или sol::metatableуказал на соответствующую sol3 метатаблицы. Это полностью разъединит и очистит внутренние структуры поиска sol3 и ключевую информацию.
5327
5328функции времени выполнения
5329Вы можете добавлять функции во время выполнения ко всему классу (не к отдельным объектам). Установите имя под метатабельным именем, которое вы привязали new_usertypeк объекту. Например:
5330
5331runtime_extension.cpp
5332
5333#define SOL_ALL_SAFETIES_ON 1
5334#include <sol/sol.hpp>
5335
5336#include <iostream>
5337
5338struct object {
5339 int value = 0;
5340};
5341
5342int main (int, char*[]) {
5343
5344 cout << "==== runtime_extension =====" << endl;
5345
5346 sol::state lua;
5347 lua.open_libraries(sol::lib::base);
5348
5349 lua.new_usertype<object>( "object" );
5350
5351 // runtime additions: through the sol API
5352 lua["object"]["func"] = [](object& o) { return o.value; };
5353 // runtime additions: through a lua script
5354 lua.script("function object:print () print(self:func()) end");
5355
5356 // see it work
5357 lua.script("local obj = object.new() \n obj:print()");
5358
5359 return 0;
5360}
5361Заметка
5362
5363Вы не можете добавлять функции к отдельному объекту. Вы можете добавлять функции только ко всему классу / типу пользователя.
5364
5365перегрузка
5366Функции, установленные для пользовательского типа, поддерживают перегрузку. Смотрите здесь для примера.
5367
5368наследство
5369Sol может корректировать указатели от производных классов до базовых классов во время выполнения, но у него есть некоторые предостережения, основанные на том, что вы компилируете:
5370
5371Если у вашего класса нет сложного виртуального наследования или множественного наследования, вы можете попытаться ускользнуть с повышением производительности, не указав какие-либо базовые классы и не выполнив какие-либо проверки приведения. (Что означает «complex ™»? Спросите документацию вашего компилятора, если вы в этом разбираетесь.)
5372
5373Для остальных из нас безопасных людей: Вы должны указать sol::base_classesтег с sol::bases<Types...>()аргументом, где Types...находятся все базовые классы одного типа T, из которого вы делаете пользовательский тип.
5374
5375Зарегистрируйте базовые классы явно.
5376
5377Заметка
5378
5379Всегда указывайте свои базы, если вы планируете извлекать базовый класс напрямую, используя абстракцию sol, а не сами себя.
5380
5381наследство.cpp
5382
5383#define SOL_ALL_SAFETIES_ON 1
5384#include <sol/sol.hpp>
5385
5386struct A {
5387 int a = 10;
5388 virtual int call() { return 0; }
5389 virtual ~A(){}
5390};
5391struct B : A {
5392 int b = 11;
5393 virtual int call() override { return 20; }
5394};
5395
5396int main (int, char*[]) {
5397
5398 sol::state lua;
5399
5400 lua.new_usertype<B>( "A",
5401 "call", &A::call
5402 );
5403
5404 lua.new_usertype<B>( "B",
5405 "call", &B::call,
5406 sol::base_classes, sol::bases<A>()
5407 );
5408
5409 return 0;
5410}
5411Заметка
5412
5413Вы должны перечислить ВСЕ базовые классы, включая (если они были) базовые классы A, а также базовые классы этих базовых классов и т. Д., Если вы хотите, чтобы sol / Lua обрабатывал их автоматически.
5414
5415Заметка
5416
5417Sol не поддерживает преобразование из базового класса в производный класс во время выполнения.
5418
5419Предупреждение
5420
5421Укажите все переменные-члены базового класса и функции-члены, чтобы избежать предостережений текущей реализации относительно автоматического поиска базового члена. В настоящее время sol пытается связать методы и переменные базового класса с их производными классами с помощью недокументированной неподдерживаемой функции, если вы укажете это sol::bases<...>. К сожалению, это может происходить за счет производительности, в зависимости от того, «далеко» ли база от производного класса в списке поиска баз. Если вы не хотите страдать от снижения производительности, пока мы сглаживаем изломы в реализации (и хотим, чтобы он оставался постоянным всегда), укажите все базовые методы для производного класса в списке методов, который вы пишете. В будущем мы надеемся, что с размышлениями нам не придется беспокоиться об этом.
5422
5423автоматические типы пользователей
5424Типы пользователей автоматически регистрируют специальные функции, независимо от того, связаны они или нет с помощью new_usertype . Вы можете отключить это, специализируя sol::is_automagical<T>черту шаблона:
5425
5426struct my_strange_nonconfirming_type { /* ... */ };
5427
5428namespace sol {
5429 template <>
5430 struct is_automagical<my_strange_nonconforming_type> : false_type {};
5431}
5432наследование + перегрузка
5433Несмотря на то, что перегрузка поддерживается независимо от предостережений наследования или нет, текущая версия sol имеет стиль перегрузки по первому совпадению при первом вызове, когда дело доходит до наследования. Сначала поместите функции с наиболее производными аргументами, чтобы получить ожидаемое совпадение или приведение внутри промежуточной функции C ++, и вызовите нужную функцию.
5434
5435скорость компиляции
5436Заметка
5437
5438MSVC и clang / gcc могут понадобиться дополнительные флаги компилятора для обработки компиляции с широким использованием пользовательских типов. Смотрите: документацию по ошибкам для более подробной информации.
5439
5440Примечание о производительности
5441Заметка
5442
5443Обратите внимание, что производительность для вызовов функций-членов снижается из-за фиксированных накладных расходов, если вы также связываете переменные и функции-члены. Это чисто ограничение реализации Lua, и, к сожалению, с этим ничего нельзя поделать. Однако если вы связываете только функции, а не переменные, sol автоматически оптимизирует время выполнения Lua и даст вам максимально возможную производительность. Пожалуйста, учтите простоту использования и обслуживания кода, прежде чем превращать все в функции.
5444
5445память типа пользователя
5446расположение в памяти пользовательских типов
5447
5448Заметка
5449
5450Sol не берет на себя владение необработанными указателями, возвращенными из функций или установленными через setфункции. Верните значение, a unique_ptr, a shared_ptrнекоторого вида или подключите уникальные черты usertypes, чтобы работать для определенной структуры дескриптора, которую вы используете (AKA, для boost::shared_ptr).
5451
5452Пользовательские данные, сгенерированные sol, имеют определенную компоновку, в зависимости от того, как sol распознает переданные в него пользовательские данные. Все упомянутые метатируемые имена генерируются из имени самого класса. Обратите внимание, что мы используем 1 метатабель для 3 перечисленных ниже стилей, плюс 1 дополнительный метатабль, который используется для фактической таблицы, которую вы связываете с именем при вызове table::new/set_(simple_)usertype.
5453
5454В общем, мы всегда вставляем T*первые sizeof(T*)байты, поэтому любая инфраструктура, которая извлекает эти первые байты, ожидая, что указатель будет работать. Остальные данные имеют различные выравнивания и содержимое в зависимости от того, для чего они используются и как они используются.
5455
5456Предупреждение
5457
5458Расположение памяти, описанное ниже, не учитывает выравнивание. sol3 теперь учитывает выравнивание и выравнивает память, что важно для некорректно работающих распределителей и типов, которые плохо выровнены по размеру указателя в их системе. Если вам необходимо получить соответствующие выравнивания для usertypes , хранящегося в USERDATA указателей, пожалуйста , используйте функцию подробно с именем sol::detail::align_usertype_pointer, sol::detail::align_usertypeи sol::detail::align_usertype_unique. Это сместит void*указатель на соответствующую величину, чтобы достичь определенного раздела в памяти. Практически во всех других случаях использования используйте , а затем установите указатель в нужное место.void* memory = lua_touserdata(L, index);memory = sol::detail::align_usertype_pointer( memory );
5459
5460Предупреждение
5461
5462Диаграммы и пояснения ниже гарантированно будут работать 100% времени, если вы определите SOL_NO_MEMORY_ALIGNMENT . Имейте в виду, что это может привести к смещению операций чтения / записи, что может привести к сбою некоторых старых процессоров и вызвать предупреждения статического анализатора / инструментария, например Clang's Address Sanitizer (ASan).
5463
5464Чтобы получить T
5465Если вы хотите получить T*указатель на данные, управляемые пользовательскими данными sol3, и не используете для этого абстракции sol3 (например, возиться с простым API Lua C), просто используйте lua_touserdataдля получения void*указателя. Затем выполните a . Каждый тип, помещенный в C ++, который классифицируется как пользовательские данные (например, все определяемые пользователем объекты, которые не охватываются основными типами абстракции стека), может быть получен в этом формате, независимо от того, являются ли они значениями, указателями или . Причины, по которым это работает, приведены ниже.T* object_pointer = *static_cast<T**>(the_void_pointer);unique_ptr
5466
5467Для T
5468Они классифицируются с метатабельным именем, обычно полученным из самого имени класса.
5469
5470Расположение данных для ссылок выглядит следующим образом:
5471
5472| T* | T |
5473^-sizeof(T*) bytes-^-sizeof(T) bytes, actual data-^
5474Lua очистит саму память, но не знает ни о какой семантике уничтожения, которую может навязать T, поэтому, когда мы уничтожаем эти данные, мы просто вызываем деструктор, чтобы уничтожить объект, и оставляем изменения памяти в lua для обработки после «__gc» метод выхода.
5475
5476Для T*
5477Они классифицируются как отдельная T*метатабельная, по сути, «справочная» таблица. Вещи, передаваемые sol в качестве указателя или a reference<T>, считаются ссылками и, следовательно, __gcпо умолчанию не имеют метода (сборки мусора). Все необработанные указатели не принадлежат указателям в C ++. Если вы работаете с C API, обеспечьте обертку вокруг указателей, которые должны владеть данными, и используйте идиомы конструктора / деструктора (например, с внутренним unique_ptr) для поддержания чистоты.
5478
5479Структура данных для данных, которые относятся только к следующему:
5480
5481| T* |
5482^-sizeof(T*) bytes-^
5483Вот и все. Не нужно называть семантику уничтожения.
5484
5485Для и unique_ptr<T, D>shared_ptr<T>
5486Они классифицируются как «уникальные типы пользователей» , и для них также есть специальные метатаблицы. Специальный метатабель генерируется либо при добавлении пользовательского типа в Lua с помощью set_usertype, либо при первом нажатии одного из этих специальных типов. В дополнение к данным, функция удаления, которая понимает следующий макет, внедряется в макет пользовательских данных.
5487
5488Расположение данных для этих типов типов выглядит следующим образом:
5489
5490| T* | void(*)(void*) function_pointer | T |
5491^-sizeof(T*) bytes-^-sizeof(void(*)(void*)) bytes, deleter-^- sizeof(T) bytes, actal data -^
5492Обратите внимание, что мы помещаем специальную функцию удаления перед фактическими данными. Это связано с тем, что пользовательское средство удаления должно знать, где находится смещение данных и где находится специальное средство удаления. Другими словами, поля фиксированного размера располагаются перед любыми данными переменного размера (T может быть известен во время компиляции, но при сериализации в Lua таким образом он становится объектом времени выполнения). Sol просто необходимо знать, T*как работают пользовательские данные (и метаданные пользователя), все остальное - для сохранения семантики построения / разрушения.
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502Это наконец происходит. После переговоров C ++ Now и CppCon 2018, а также большого количества работы и обратной связи (спасибо всем, кто отправлял электронные письма, а также всем участникам Patron и Discord, которые участвовали), sol3 теперь полностью завершен.
5503
5504Что это значит?
5505sol3 в основном совместим с предыдущим sol2. Это означает, что я больше не буду работать над sol2 (sol2 уже полностью готов к работе уже почти год и какое-то время получал в основном исправления ошибок). Все критические изменения идут в сторону sol3. Самые большие изменения:
5506
5507Для пользователей существует новое блестящее пространство точек настройки с явным обещанием, что как автор библиотеки я никогда не напишу ничего, что могло бы потенциально конкурировать с вашими точками настройки. Пользователям sol2 нужно будет перенести свои точки настройки на этот новый слой (и это нормально: исправление буквально удаляет кучу строк кода и больше не требует их записи в пространстве имен sol2).
5508В настоящее время наблюдается огромный прирост производительности для всех людей, которые полагались на ранее рискованное наследование пользовательских типов. Это так быстро, как я мог сделать это без отражения, специфических для платформы хаков и сборочных уловок. После того, как Reflection завершит прохождение голосования по PD TS и будет одобрен для C ++ 20/23, и компиляторы его развернут, я могу реализовать это с новыми механизмами sol3 без нарушений обратной совместимости и получить последние падения производительности, которые позволят пользователям достичь уровней производительности наследования SWIG без какой-либо дополнительной разметки.
5509Пользовательские типы контейнеров имеют лучшую обработку и значения по умолчанию в некоторых избранных случаях, а также немного лучшую производительность. Мы также исправили более старый класс ошибок, которые, тем не менее, ломали изменения, которые я не мог коснуться в sol2: теперь все чисто.
5510Интеграция с CMake теперь является Modern Top Tier ™. Теперь вы можете получить sol2, сингл или сгенерированный сингл. Вы получаете цель sol2, делая sol2::sol2, sol2::sol2_singleпосле add_subdirectory(sol/single)или sol2::sol2_single_generatedпосле add_subdirectory(sol/single). Мы также значительно улучшили гигиену заголовков и аналогичные с новыми тестами компиляции и добавили целый новый набор тестов во время выполнения. Значение по умолчанию для включения sol2 также теперь #include <sol/sol.hpp>, следуя boost::стилю включения, чтобы помочь предотвратить столкновения.
5511C ++ 17 включен. Определения, включающие возможности C ++ 17, все еще существуют из-за чистой лени: теперь это библиотека C ++ 17.
5512Производительность хороша ™.
5513Поскольку это значительное увеличение версии, часть кода, написанного людьми ранее, сломается. Вот хорошая новость: большая часть вашего кода не сломается, и ничего более фундаментального или ядра в sol2 на самом деле не сломалось. Просто вещи, которые были уже ужасны.
5514
5515Пользовательские удаления и очистка
5516Это были первоочередные цели, которые нужно было исправить, но в конечном итоге это было легко, так как в основном это было связано с моим [delete]ключом и увлечением тем, как вещи исчезают.
5517
5518new_simple_usertypeи simple_usertypeобъекты больше не существуют. Они были хакерами для увеличения пропускной способности времени компиляции, в то же время заставляя пользователя оплачивать затраты времени выполнения в некоторых случаях Больше не нужно, и код работает так быстро, как может быть всегда: это было удалено .
5519sol::usertype<T>«Я беру миллион вещей и создаю несколько слоев шаблонного дерьма и ставлю компилятор на колени с помощью конструктора AST OooOooh! объемом 12 ГБ!». sol::usertypeтеперь это фактический тип мета-таблицы, который ведет себя как обычный sol::table, где вы можете устанавливать / получать вещи. Вонкий конструктор с set_usertypeбольше не существует. Как и должно быть: я сожалею, что когда-либо писал это.
5520Весь неправильный код приводит к разрыву сборки, так как я предпочитаю, чтобы я ломал вашу сборку, а не позволял вам обновляться и затем молча делал неправильные вещи. Крутая вещь в отношении поломок здесь состоит в том, что это не просто разрывы без передышки: у всего, что сломано, теперь есть лучшие способы сделать это, который компилируется быстрее (хотя я не обещаю, что у вас не будет кучи компилятора 12 ГБ, особенно если ты небрежен).
5521
5522Одна вещь, которую я не сломал, была lua.new_usertype<blah>( ctor, "key", value, "key2", sol::property(...), /* LITERALLY EVERYTHING */ );. Это будет продолжать работать. И это также поставит ваш компилятор на колени снова, что не очень приятно с вашей стороны. Пожалуйста, рассмотрите возможность использования
5523
5524struct blah {
5525 int a;
5526 bool b;
5527 char c;
5528 double d;
5529 /* ... */
5530};
5531
5532constexr int some_static_class_value = 58;
5533
5534int main () {
5535 sol::state lua;
5536
5537 sol::usertype<blah> metatable = lua.new_usertype<blah>(
5538 /* just some constructor and destructor stuff maybe*/
5539 );
5540
5541 metatable["a"] = blah::a;
5542 metatable["b"] = sol::property(
5543 [](blah& obj) { return obj.b; },
5544 [](blah& obj, bool val) { obj.b = val; if (obj.b) { ++obj.a; } }
5545 );
5546 metatable["super_c"] = sol::var(some_static_class_value);
5547}
5548Скорость выполнения получающейся привязки остается той же, благодаря некоторым серьезным оптимизациям, которые я выполняю, чтобы убедиться, что мы сериализуем то, что максимально близко к оптимизированной карте, unique_ptr<char[]>которую callable or variableя мог бы создать. Пользовательские типы теперь также могут обрабатывать не строковые ключи, что позволяет кому-то индексировать в них пользовательские данные (указатели и тому подобное), целые числа и другие точки данных без необходимости переопределять методы __indexили __newindex.
5549
5550Количество улучшений действительно ошеломляет, правда ...! Я мог бы написать целую статью о детерминированных во время выполнения качествах, которые мы сейчас внедрили в sol2, благодаря таким вещам, как наличие объекта, unordered_mapкоторый больше не нужно выделять для поиска ключей без необходимости прибегать к boost::своим собственным или взламывать их unordered_map. Это означает, что поддержка людей, которые использовали sol2 для целей обработки в реальном времени, остается на месте, гарантируя, что у них есть путь времени исполнения с 0 выделениями, который они могут использовать для пользовательских типов и тому подобное.
5551
5552Новые настройки: Ваш собственный задний двор (и мой газон)
5553Точки настройки также были плохими в sol2. Иногда пользователи хотели изменить, как система обрабатывает фундаментальные типы: они не могли без переписывания моего кода. Я хорошо говорю о том, почему точки специализации структуры как фундаментальная абстракция плохи для такой библиотеки, как sol2, в моем видео CppCon 2018 и о том, как мне приходится бороться, чтобы сохранить чистое разделение.
5554
5555sol::stack::pusher, sol::stack::checkerИ т.д. - борьба со мной , чтобы убедиться , что я не наступайте на ваши настройки точек специализации действительно отстой.
5556Специализация этих старых имен сейчас не компилируется. Старые имена больше не существуют, чтобы убедиться, что это была серьезная ошибка компилятора, и что внесенные мной изменения не изменили время выполнения вашей программы и не дадут вам день отладочного приключения.
5557Производительность не изменилась, но небрежный код наверняка изменился. Этот кусок кода, заполненного шаблонами, теперь можно заменить:
5558
5559struct two_things {
5560 int a;
5561 bool b;
5562};
5563
5564namespace sol {
5565
5566 // First, the expected size
5567 // Specialization of a struct
5568 template <>
5569 struct lua_size<two_things> : integral_constant<int, 2> {};
5570
5571 // Then, specialize the type
5572 // this makes sure Sol can return it properly
5573 template <>
5574 struct lua_type_of<two_things> : integral_constant<sol::type, sol::type::poly> {};
5575
5576 // Now, specialize various stack structures
5577 namespace stack {
5578
5579 template <>
5580 struct checker<two_things> {
5581 template <typename Handler>
5582 static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
5583 int absolute_index = lua_absindex(L, index);
5584 bool success = stack::check<int>(L, absolute_index, handler)
5585 && stack::check<bool>(L, absolute_index + 1, handler);
5586 tracking.use(2);
5587 return success;
5588 }
5589 };
5590
5591 template <>
5592 struct getter<two_things> {
5593 static two_things get(lua_State* L, int index, record& tracking) {
5594 int absolute_index = lua_absindex(L, index);
5595 int a = stack::get<int>(L, absolute_index);
5596 bool b = stack::get<bool>(L, absolute_index + 1);
5597 tracking.use(2);
5598 return two_things{ a, b };
5599 }
5600 };
5601
5602 template <>
5603 struct pusher<two_things> {
5604 static int push(lua_State* L, const two_things& things) {
5605 int amount = stack::push(L, things.a);
5606 amount += stack::push(L, things.b);
5607 return amount;
5608 }
5609 };
5610
5611 }
5612}
5613С этим намного более коротким и намного более замечательным фрагментом:
5614
5615struct two_things {
5616 int a;
5617 bool b;
5618};
5619
5620template <typename Handler>
5621bool sol_lua_check(sol::types<two_things>, lua_State* L, int index,
5622Handler&& handler, sol::stack::record& tracking) {
5623 int absolute_index = lua_absindex(L, index);
5624 bool success = sol::stack::check<int>(L, absolute_index, handler)
5625 && sol::stack::check<bool>(L, absolute_index + 1, handler);
5626 tracking.use(2);
5627 return success;
5628}
5629
5630two_things sol_lua_get(sol::types<two_things>, lua_State* L, int index,
5631sol::stack::record& tracking) {
5632 int absolute_index = lua_absindex(L, index);
5633 int a = sol::stack::get<int>(L, absolute_index);
5634 bool b = sol::stack::get<bool>(L, absolute_index + 1);
5635 tracking.use(2);
5636 return two_things{ a, b };
5637}
5638
5639int sol_lua_push(sol::types<two_things>, lua_State* L, const two_things& things) {
5640 int amount = sol::stack::push(L, things.a);
5641 amount += sol::stack::push(L, things.b);
5642 return amount;
5643}
5644С гарантией того, что любые будущие SFINAE и обработчики, которые я напишу, всегда будут «backend» и «default»: если вы напишите один в новой парадигме, это всегда переопределит мое поведение. Вы даже можете переопределить мое поведение для фундаментальных типов, таких как int64_t. У пользователей были проблемы с тем, как я работаю с целыми числами и другими вещами из-за того, что все числа Lua постоянно удваиваются: теперь им не нужно прибегать к значениям по умолчанию библиотеки или заставлять меня писать больше конфигурационных макросов. Они могут просто изменить его для своего приложения, что довольно здорово. Он также хранит всех вас, юных похитителей, у вас на заднем дворе, и с моего газона, да!
5645
5646Обратите внимание, что сокращение кода буквально отбирает пространства имен и кучу других грязных специализаций шаблонов. На самом деле, это просто написание ваших собственных функций сейчас. И эти функции не должны находиться в шаблонах: вы можете поместить объявление в заголовок, экспортировать их и многое другое! ( HandlerШаблон выше, потому что я ленивый.) В sol3 также есть полноценное обязательство и поддержка <sol/forward.hpp>заголовка, который заранее объявляет все необходимое, чтобы сработали вышеуказанные объявления (больше скорости компиляции, nyeeoooom ??!).
5647
5648Хорошо, но Feature Complete не означает, что выпущен ...?
5649Ах, ты меня понял. Это функция завершена, но она не готова к выпуску. Код в порядке, но:
5650
5651Документация должна быть обновлена для того, как делается новый пользовательский тип. Это включает в себя учебные пособия и справочную документацию по API. Все примеры построены как часть тестов, которые проходят! Это означает, что примеры пока могут служить достаточно приличной документацией. Помните, что вы можете заглянуть в Sol2 Discord: мы очень полезны и помогаем людям не только начать, но и решать сложные проблемы! Вы также можете @thephantomderp в Твиттере, если вы придурок.
5652Справочная документация по API содержит код для вставки или написания от руки, который правильно указывает семантику sol2. Вероятно, было бы лучше, если бы я мог просто ссылаться на фактический блок конструкторов в коде, а не создавать (заполненную опечаткой) разметку.
5653Я хочу сделать блестящий логотип sol3. ... Но я отстой в рисовании. Итак, это вещь.
5654Инфраструктура тестирования отстой. Потому что мои навыки CMake отстой.
5655Мне нужно пометить vcpkg, Conan и, возможно, даже build2, чтобы убедиться, что у них всех есть пакеты, готовые к переходу на sol3 в какой-то момент в отдаленном будущем (совершенно необязательно, мне очень надоели менеджеры пакетов, системы мета-сборки и строить системы прямо сейчас).
5656Это действительно так. Есть несколько небольших мест, где мне нужно изгнать демона-компилятора tupleи его множество грубых конструкторов, в основном, проверяя, находится ли sizeof...(Args) == 2в if constexprблоке, и немедленно отправляя его обработчику, не упаковывая вещи в forward_as_tupleпервый. Я также могу сэкономить массу откатов и разложений компилятора, создав частичные специализации с 1, 2 и 3 ключами для моих типов прокси-таблиц, поэтому мне больше не нужно рвать кортежи кортежей в этих вещах для хранения ленивых ключей: еще не видел 4 прокси-запросов. (И если они у вас есть без сохранения посредников, вы заслуживаете демонов-компиляторов, которые внедряются в ваш код и весь стыд, который с ним связан!).
5657
5658Существует также извивающийся левиафан, который я имею в виду для SFINAE-и-tag-dispatch-at-the-time, для оптимизации функций в sol2, который, вероятно, можно свести к некоторым, if constexprтак что .set_functionвызов не так уж и во время компиляции. дорогой тоже.
5659
5660if constexpr? Но Derpstorm, как насчет моего {старого компилятора здесь} ?!
5661Я давным-давно высказал предположение, что sol3 будет использовать технологию C ++ 17 (например, почти 2 года назад?), В основном, чтобы сэкономить мне скорость компиляции и здравый смысл. Поскольку sol3 - это библиотека с открытым исходным кодом, я делаю это для удовольствия, а не для выгоды. Что переводится как:
5662
5663Requests Потяните запросы добро пожаловать! ?
5664
5665Я должен закончить школу, и я буду интернировать в течение лета. Sol2 уже получил широкое распространение в отрасли, сэкономил разработчикам миллионы на бесполезном оттоке Lua API и принес множество крупных стеков наличности в магазины по всему миру. Если вашей компании нужна специальная версия типа «снежинка» для C ++ 11 или - «Господь на небесах» - C ++ 03, пришлите мне электронное письмо, и мы сможем разработать контракт на перенос sol3 в вашу старую стабильную инфраструктуру. (Даже если это дряхлый, я не буду судить: я только что провел последнюю неделю, рассматривая различные варианты Ubuntu и Debian и CentOS и их компиляторов, а также мусор Travis и Appveyor. Я ненавижу мир, как есть, но я полностью понимаю, почему Вы придерживаетесь своей 4-летней машины без поддержки! ... Немного. Хорошо, я буду честен. Есть некоторое суждение. Но только немного, я клянусь!)
5666
5667Это все на данный момент. Я буду работать над документацией sol3, некоторыми усовершенствованиями инфраструктуры тестирования, так что она будет полезна для всех сумасшедших инструментов, которые я хочу сделать, и готовлюсь побеспокоить кресло SG16 - Тома Хонерманна - и легендарного создателя libogonek - Robot - с много вопросов по интерфейсу Unicode в ближайшее время! А потом это школа, и все может затихнуть.
5668
5669Или ... так ли это? ?
5670
5671
5672
5673
5674Потоки
5675
5676int main(int argc, char* argv[]) {
5677 state lua;
5678 lua.open_libraries();
5679 sol::function transferred_into;
5680 lua["f"] = [&lua, &transferred_into](sol::object t, sol::this_state this_L) {
5681 cout << "state of main : " << (void*)lua.lua_state() << endl;// адрес в памяти.
5682 cout << "state of function : " << (void*)this_L.lua_state() << endl;
5683 // pass original lua_State* (or sol::state/sol::state_view)
5684 // transfers ownership from the state of "t",
5685 // to the "lua" sol::state
5686 transferred_into = sol::function(lua, t);
5687 };
5688
5689 lua.script(R"(
5690 i = 0
5691 function test()
5692 co = coroutine.create(
5693 function()
5694 local g = function() i = i + 1 end
5695 f(g)
5696 g = nil
5697 collectgarbage()
5698 end
5699 )
5700 coroutine.resume(co)
5701 co = nil
5702 collectgarbage()
5703 end
5704 )");
5705
5706 // give it a try
5707 lua.safe_script("test()");
5708 // should call 'g' from main thread, increment i by 1
5709 transferred_into();
5710 // check
5711 int i = lua["i"];
5712 cout << i << endl;
5713 return 0;
5714};
5715
5716const char* LUA = R"(
5717 function loop()
5718 while counter ~= 30
5719 do
5720 coroutine.yield(counter);
5721 print(counter)
5722 counter = counter + 1;
5723 end
5724 return counter
5725 end
5726
5727)";
5728
5729int main(int argc, char* argv[]) {
5730 state lua;// Lua состояние.
5731 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
5732
5733 lua.script(LUA);
5734 coroutine cr = lua["loop"];
5735
5736 // мы хотим 10 значений, и мы только хотим запустить, если сопрограмма "cr" действительна
5737 // Альтернатива: счетчик < 10 & & cr.действительный()
5738 //// Вызов сопрограммы, выполняет вычисления и затем приостанавливает
5739 //for (int counter = 0; counter < 10 && cr; ++counter) {
5740 // int value = cr();
5741 // cout << value << endl;
5742 //}
5743
5744 return 0;
5745};
5746
5747const char* LUA = R"(
5748
5749 function loop()
5750 for i = 1, 10 do
5751 print(i)
5752 coroutine.yield()
5753 end
5754end
5755)";
5756
5757int main(int argc, char* argv[]) {
5758 state lua;// Lua состояние.
5759 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
5760
5761 lua.script(LUA);
5762 coroutine cr = lua["loop"];
5763
5764 //мы хотим 10 значений, и мы только хотим запустить, если сопрограмма "cr" действительна
5765 //Альтернатива: счетчик < 10 & & cr.действительный()
5766 //Вызов сопрограммы, выполняет вычисления и затем приостанавливает
5767 for (int counter = 0; counter < 10 && cr; ++counter) {
5768 cr.call();
5769
5770 }
5771
5772 return 0;
5773};
5774
5775const char* LUA = R"(
5776 function main(x, y, z)
5777 -- do something
5778 coroutine.yield(20)
5779 -- do something else
5780 -- do ...
5781 print(x, y, z)
5782end
5783 function main2(x, y)
5784 coroutine.yield(10)
5785 print(x, y)
5786end
5787 start_thread(main, 10, 12, 8)
5788 start_thread(main2, 1, 2)
5789)";
5790
5791int main(int argc, char* argv[]) {
5792 state lua;
5793 vector<coroutine> threads;
5794 lua.open_libraries(lib::base, lib::coroutine);
5795
5796 thread runner_thread = thread::create(lua);
5797
5798 lua.set_function("start_thread",
5799 [&runner_thread, &threads](sol::function f, variadic_args va){
5800 // Вы всегда должны получить текущее состояние.
5801 state_view runner_thread_state = runner_thread.state();
5802 // Поместите задачу в наш список задач, чтобы сохранить ее и отслеживать ее.
5803 size_t threads_index = threads.size();
5804 threads.emplace_back(runner_thread_state, f);
5805 // создает объект непосредственно в конце вектора, т.е. без лишнего копирования.
5806 coroutine& run_thread = threads[threads_index];
5807 // вызов сопрограммы с аргументами, которые пришли.
5808 // из главного потока / другой поток.
5809 // толкатель для 'variadic_args' и других типов почвы перенесет
5810 // аргументы из вызывающего потока.
5811 // поток бегунка автоматически для вас.
5812 // используя lua_xmove` внутренне.
5813 int wait = run_thread(va);
5814 cout << "First thread " << wait << endl;// Когда вы вызываете его снова, вам не нужны новые аргументы
5815 // (они остаются неизменными с первого вызова)
5816 run_thread();
5817 cout << "Second thread " << wait << endl;}
5818 );
5819
5820lua.script(LUA);
5821
5822cout << endl;
5823
5824 return 0;
5825};
5826using namespace sol; const char* LUA = R"(
5827 function main(x)
5828 -- do something
5829 coroutine.yield(20)
5830 -- do something else
5831 -- do ...
5832 print(x)
5833end
5834 function main2(x)
5835 coroutine.yield(10)
5836 print(x)
5837end
5838 start_thread(main, 10)
5839 start_thread(main2, 1)
5840)";
5841
5842int main(int argc, char* argv[]) {
5843 state lua;
5844 vector<coroutine> threads;
5845 lua.open_libraries(lib::base, lib::coroutine);
5846
5847 thread runner_thread = thread::create(lua);
5848 lua.set_function("start_thread", [&runner_thread, &threads](sol::function f, variadic_args va) {
5849 // Вы всегда должны получить текущее состояние.
5850 state_view runner_thread_state = runner_thread.state(); // Поместите задачу в наш список задач,
5851 //чтобы сохранить ее и отслеживать ее.
5852 size_t threads_index = threads.size();
5853 threads.emplace_back(runner_thread_state, f);// создает объект непосредственно в конце вектора, т.е. без лишнего копирования.
5854 coroutine& run_thread = threads[threads_index];
5855 // вызов сопрограммы с аргументами, которые пришли. из главного потока / другой поток.
5856 // толкатель для 'variadic_args' и других типов почвы перенесет аргументы из вызывающего потока.
5857 // поток бегунка автоматически для вас. используя lua_xmove` внутренне.
5858 int wait = run_thread(va);
5859 cout << "First thread " << wait << endl;// Когда вы вызываете его снова, вам не нужны новые аргументы
5860 // (они остаются неизменными с первого вызова)
5861 run_thread();
5862 cout << "Second thread " << wait << endl; }
5863 );
5864
5865 lua.script(LUA);
5866
5867 cout << endl;
5868
5869 return 0;
5870};
5871const char* LUA = R"(
5872 function main(x)
5873 coroutine.yield(20)
5874 print(x)
5875end
5876 function main2(x)
5877 coroutine.yield(10)
5878 print(x)
5879end
5880 start_thread(main, 10)
5881 start_thread(main2, 1)
5882)";
5883
5884int main(int argc, char* argv[]) {
5885 state lua;
5886 vector<coroutine> threads;
5887 lua.open_libraries(lib::base, lib::coroutine);
5888
5889 thread runner_thread = thread::create(lua);
5890 lua.set_function("start_thread",[&runner_thread, &threads](sol::function f, variadic_args va) {
5891 // Вы всегда должны получить текущее состояние.
5892 state_view runner_thread_state = runner_thread.state(); // Поместите задачу в наш список задач,
5893 //чтобы сохранить ее и отслеживать ее.
5894 size_t threads_index = threads.size();
5895 threads.emplace_back(runner_thread_state, f);// создает объект непосредственно в конце вектора, т.е.
5896 //.без лишнего копирования.
5897 coroutine& run_thread = threads[threads_index];
5898 // вызов сопрограммы с аргументами, которые пришли. из главного потока / другой поток.
5899 // толкатель для 'variadic_args' и других типов почвы перенесет аргументы из вызывающего потока.
5900 // поток бегунка автоматически для вас. используя lua_xmove` внутренне.
5901 int wait = run_thread(va);
5902 //cout << "First thread " << wait << endl;// Когда вы вызываете его снова, вам не нужны новые аргументы
5903 // (они остаются неизменными с первого вызова)
5904 run_thread(); //cout << "Second thread " << wait << endl;
5905 }
5906 );
5907
5908 lua.script(LUA);
5909
5910 cout << endl;
5911
5912 return 0;
5913};
5914const char* LUA1 = R"(
5915while true do
5916 print()
5917end
5918)";
5919const char* LUA = R"(
5920while true do
5921 print('Hello world!')
5922end
5923)";
5924int main(int argc, char* argv[]) {
5925 state lua;// Lua состояние.
5926 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
5927 thread run = thread::create(lua.lua_state());
5928 state_view runstate = run.state();
5929 runstate.script(LUA1);
5930 lua.script(LUA);
5931 return 0;
5932};
5933
5934struct coro_test {
5935 string identifier;
5936 reference obj;
5937
5938 coro_test(this_state L, string id) : identifier(id), obj(L, lua_nil) {
5939 }
5940
5941 void store(table ref) {
5942 // must be explicit
5943 obj = reference(obj.lua_state(), ref);
5944 }
5945
5946 void copy_store(table ref) {
5947 // must be explicit
5948 obj = reference(obj.lua_state(), ref);
5949 }
5950
5951 reference get() {
5952 return obj;
5953 }
5954
5955 ~coro_test() {
5956 }
5957};
5958
5959struct coro_test_implicit {
5960 string identifier;
5961 main_reference obj;
5962
5963 coro_test_implicit(this_state L, string id) : identifier(id), obj(L, lua_nil) {
5964 }
5965
5966 void store(table ref) {
5967 // main_reference does the state shift implicitly
5968 obj = move(ref);
5969 lua_State* Lmain = main_thread(ref.lua_state());
5970 //REQUIRE(obj.lua_state() == Lmain);
5971 }
5972
5973 void copy_store(table ref) {
5974 // main_reference does the state shift implicitly
5975 obj = ref;
5976 lua_State* Lmain = main_thread(ref.lua_state());
5977 // REQUIRE(obj.lua_state() == Lmain);
5978 }
5979
5980 reference get() {
5981 return obj;
5982 }
5983
5984 ~coro_test_implicit() {
5985 }
5986};
5987
5988const auto& script = R"(counter = 20
5989function loop()
5990 while counter ~= 30
5991 do
5992 coroutine.yield(counter);
5993 counter = counter + 1;
5994 end
5995 return counter
5996end
5997)";
5998
5999int main(int argc, char* argv[]) {
6000 state lua;
6001 lua.open_libraries(lib::base, lib::table, lib::coroutine);
6002 {
6003 auto code = R"(
6004unpack = unpack or table.unpack
6005function loop()
6006 local i = 0
6007 while true do
6008 print("pre-yield in loop")
6009 coroutine.yield(i)
6010 print("post-yield in loop")
6011 i = i+1
6012 end
6013end
6014loop_th = coroutine.create(loop)
6015loop_res = function(...)
6016 returns = { coroutine.resume(loop_th, ...) }
6017 return unpack(returns, 2)
6018end
6019)";
6020 auto result = lua.safe_script(code, script_pass_on_error);
6021 // REQUIRE(result.valid());
6022 }
6023
6024 // Resume from lua via thread and coroutine
6025 thread runner_thread = lua["loop_th"];
6026 state_view runner_thread_state = runner_thread.state();
6027 auto test_resume = [&runner_thread_state]() {
6028 coroutine cr = runner_thread_state["loop"];
6029 stack::push(runner_thread_state, 50);
6030 stack::push(runner_thread_state, 25);
6031 int r = cr();
6032 return r;
6033 };
6034 lua.set_function("test_resume", ref(test_resume));
6035
6036 // Resume via getting a function from the state
6037 function test_resume_lua = lua["loop_res"];
6038
6039 // Resume via passing a function object
6040 auto test_resume_func = [](function f) {
6041 int r = f();
6042 return r;
6043 };
6044 lua.set_function("test_resume_func", ref(test_resume_func));
6045
6046 int v0 = test_resume();
6047 int s0 = runner_thread_state.stack_top();
6048 int v1 = test_resume();
6049 int s1 = runner_thread_state.stack_top();
6050 int v2;
6051 {
6052 auto result = lua.safe_script("return test_resume()", script_pass_on_error);
6053 //REQUIRE(result.valid());
6054 v2 = result;
6055 }
6056 int s2 = runner_thread_state.stack_top();
6057 int v3;
6058 {
6059 auto result = lua.safe_script("return test_resume()", script_pass_on_error);
6060 //REQUIRE(result.valid());
6061 v3 = result;
6062 }
6063 int s3 = runner_thread_state.stack_top();
6064 int v4 = test_resume_lua();
6065 int s4 = runner_thread_state.stack_top();
6066 int v5;
6067 {
6068 auto result = lua.safe_script("return test_resume_func(loop_res)", script_pass_on_error);
6069 //REQUIRE(result.valid());
6070 v5 = result;
6071 }
6072 int s5 = runner_thread_state.stack_top();
6073
6074cout << endl;
6075
6076 return 0;
6077};
6078
6079
6080struct coro_h {
6081 int x = 500;
6082 int func() {
6083 x += 1;
6084 return x;
6085 }
6086};
6087
6088struct coro_test {
6089 string identifier;
6090 sol::reference obj;
6091
6092 coro_test(sol::this_state L, string id) : identifier(id), obj(L, sol::lua_nil) {
6093 }
6094
6095 void store(sol::table ref) {
6096 // must be explicit
6097 obj = sol::reference(obj.lua_state(), ref);
6098 }
6099
6100 void copy_store(sol::table ref) {
6101 // must be explicit
6102 obj = sol::reference(obj.lua_state(), ref);
6103 }
6104
6105 sol::reference get() {
6106 return obj;
6107 }
6108
6109 ~coro_test() {
6110 }
6111};
6112
6113struct coro_test_implicit {
6114 string identifier;
6115 sol::main_reference obj;
6116
6117 coro_test_implicit(sol::this_state L, string id) : identifier(id), obj(L, sol::lua_nil) {
6118 }
6119
6120 void store(sol::table ref) {
6121 // main_reference does the state shift implicitly
6122 obj = move(ref);
6123 lua_State* Lmain = sol::main_thread(ref.lua_state());
6124// REQUIRE(obj.lua_state() == Lmain);
6125 }
6126
6127 void copy_store(sol::table ref) {
6128 // main_reference does the state shift implicitly
6129 obj = ref;
6130 lua_State* Lmain = sol::main_thread(ref.lua_state());
6131 //REQUIRE(obj.lua_state() == Lmain);
6132 }
6133
6134 sol::reference get() {
6135 return obj;
6136 }
6137
6138 ~coro_test_implicit() {
6139 }
6140};
6141
6142 const auto& script = R"(counter = 20
6143function loop()
6144 while counter ~= 30
6145 do
6146 coroutine.yield(counter);
6147 counter = counter + 1;
6148 end
6149 return counter
6150end
6151)";
6152
6153int main(int argc, char* argv[]) {
6154
6155 sol::state lua;
6156 sol::stack_guard luasg(lua);
6157
6158 lua.open_libraries(sol::lib::base, sol::lib::coroutine);
6159 auto result1 = lua.safe_script(script);
6160// REQUIRE(result1.valid());
6161 sol::coroutine cr = lua["loop"];
6162
6163 int counter;
6164 for (counter = 20; counter < 31 && cr; ++counter) {
6165 int value = cr();
6166 cout << value << endl;
6167 // REQUIRE(counter == value);
6168 }
6169 counter -= 1;
6170
6171 cout << endl;
6172
6173 return 0;
6174};
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187a separate state that can contain and run functions
6188class thread : public reference { /* ... */ };
6189sol::thread is a separate runnable part of the Lua VM that can be used to execute work separately from the main thread, such as with :doc:`coroutines<coroutine>`. To take a table or a coroutine and run it specifically on the sol::thread you either pulled out of lua or created, just get that function through the :ref:`state of the thread<thread_state>`
6190Note
6191A CPU thread is not always equivalent to a new thread in Lua: this_thread::get_id() can be the same for 2 callbacks that have 2 distinct Lua threads. In order to know which thread a callback was called in, hook into :doc:`sol::this_state<this_state>` from your Lua callback and then construct a sol::thread, passing in the sol::this_state for both the first and last arguments. Then examine the results of the status and is_... calls below.
6192free function
6193The function sol::main_thread( ... ) retrieves the main thread of the application on Lua 5.2 and above only. It is designed for code that needs to be multithreading-aware (e.g., uses multiple :doc:`threads<thread>` and :doc:`coroutines<coroutine>`).
6194Warning
6195This code function will be present in Lua 5.1/LuaJIT, but only have proper behavior when given a single argument on Lua 5.2 and beyond. Lua 5.1 does not support retrieving the main thread from its registry, and therefore it is entirely suggested if you are writing cross-platform Lua code that you must store the main thread of your application in some global storage accessible somewhere. Then, pass this item into the sol::main_thread( possibly_thread_state, my_actual_main_state )and it will select that my_actual_main_state every time. If you are not going to use Lua 5.1 / LuaJIT, you can ignore the last parameter.
6196members
6197Takes a thread from the Lua stack at the specified index and allows a person to use all of the abstractions therein. It can also take an actual thread state to make a thread from that as well.
6198This retrieves the current state of the thread, producing a :doc:`state_view<state>` that can be manipulated like any other. :doc:`Coroutines<coroutine>` pulled from Lua using the thread's state will be run on that thread specifically.
6199This function retrieves the lua_State* that represents the thread.
6200Retrieves the :doc:`thread status<types>` that describes the current state of the thread.
6201Checks to see if the thread is the main Lua thread.
6202Creates a new thread from the given a lua_State*.
6203
6204
6205
6206int main(int argc, char* argv[]) {
6207 state lua;// Lua состояние.
6208 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6209
6210
6211 const auto& my_script = R"(
6212local a,b,c = ...
6213print(a,b,c)
6214 )";
6215
6216 sol::load_result fx = lua.load(my_script);
6217 if (!fx.valid()) {
6218 sol::error err = fx;
6219 cerr << "failde to load string-based script in the program" << err.what() << endl;
6220 }
6221
6222 // prints "your arguments here"
6223 fx("your", "arguments", "here");
6224 return 0;
6225};
6226void some_function() {
6227 cout << "some function!" << endl;
6228 }
6229
6230void some_other_function() {
6231 cout << "some other function!" << endl;
6232 }
6233
6234struct some_class {
6235 int variable = 30;
6236 double member_function() {
6237 return 24.5;
6238 }
6239};
6240
6241int main(int argc, char* argv[]) {
6242 state lua;// Lua состояние.
6243 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6244
6245 // put an instance of "some_class" into lua
6246 // (we'll go into more detail about this later
6247 // just know here that it works and is
6248 // put into lua as a userdata
6249 lua.set("sc", some_class());
6250
6251 // binds a plain function
6252 lua["f1"] = some_function;
6253 lua.set_function("f2", &some_other_function);
6254
6255 // binds just the member function
6256 lua["m1"] = &some_class::member_function;
6257
6258 // binds the class to the type
6259 lua.set_function("m2", &some_class::member_function, some_class{});
6260
6261 // binds just the member variable as a function
6262 lua["v1"] = &some_class::variable;
6263
6264 // binds class with member variable as function
6265 lua.set_function("v2", &some_class::variable, some_class{});
6266
6267 lua.script(R"(
6268 f1() -- some function!
6269 f2() -- some other function!
6270
6271 -- need class instance if you don't bind it with the function
6272 print(m1(sc)) -- 24.5
6273 -- does not need class instance: was bound to lua with one
6274 print(m2()) -- 24.5
6275
6276 -- need class instance if you
6277 -- don't bind it with the function
6278 print(v1(sc)) -- 30
6279 -- does not need class instance:
6280 -- it was bound with one
6281 print(v2()) -- 30
6282 -- can set, still
6283 -- requires instance
6284 v1(sc, 212)
6285 -- can set, does not need
6286 -- class instance: was bound with one
6287 v2(254)
6288 print(v1(sc)) -- 212
6289 print(v2()) -- 254
6290 )");
6291
6292 cout << endl;
6293 return 0;
6294};
6295
6296int main(int argc, char* argv[]) {
6297 state lua;// Lua состояние.
6298 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6299 lua.script("function f (a, b, c, d) return 1 end");
6300 lua.script("function g (a, b) return a + b end");
6301
6302 // sol::function is often easier:
6303 // takes a variable number/types of arguments...
6304 sol::function fx = lua["f"];
6305 // fixed signature function<...>
6306 // can be used to tie a sol::function down
6307 function<int(int, double, int, string)> stdfx = fx;
6308
6309 int is_one = stdfx(1, 34.5, 3, "bark");
6310// c_assert(is_one == 1);
6311 int is_also_one = fx(1, "boop", 3, "bark");
6312// c_assert(is_also_one == 1);
6313
6314 // call through operator[]
6315 int is_three = lua["g"](1, 2);
6316// c_assert(is_three == 3);
6317 double is_4_8 = lua["g"](2.4, 2.4);
6318// c_assert(is_4_8 == 4.8);
6319
6320
6321 cout << endl;
6322 return 0;
6323};
6324
6325int main(int argc, char* argv[]) {
6326 state lua;// Lua состояние.
6327 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6328
6329 lua["abc_sol2"] = lua.create_table_with(
6330 0, 24
6331 );
6332
6333 sol::table inner_table = lua.create_table_with("bark", 50,
6334 // can reference other existing stuff too
6335 "woof", lua["abc_sol2"]
6336 );
6337 lua.create_named_table("def_sol2",
6338 "ghi", inner_table
6339 );
6340
6341 string code = R"(
6342 abc = { [0] = 24 }
6343 def = {
6344 ghi = {
6345 bark = 50,
6346 woof = abc
6347 }
6348 }
6349 )";
6350
6351 lua.script(code);
6352 lua.script(R"(
6353 assert(abc_sol2[0] == abc[0])
6354 assert(def_sol2.ghi.bark == def.ghi.bark)
6355 )");
6356
6357 cout << endl;
6358
6359 return 0;
6360};
6361
6362
6363 struct Doge {
6364 int tailwag = 50;
6365
6366 Doge() {
6367 }
6368
6369 Doge(int wags)
6370 : tailwag(wags) {
6371 }
6372
6373 ~Doge() {
6374 cout << "Dog at " << this << " is being destroyed..." << endl;
6375 }
6376 };
6377
6378int main(int argc, char* argv[]) {
6379 state lua;// Lua состояние.
6380 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6381 Doge dog{ 30 };
6382
6383 lua["dog"] = Doge{};
6384 lua["dog_copy"] = dog;
6385 lua["dog_move"] = move(dog);
6386 lua["dog_unique_ptr"] = make_unique<Doge>(21);
6387 lua["dog_shared_ptr"] = make_shared<Doge>(51);
6388
6389 // now we can access these types in Lua
6390 lua.new_usertype<Doge>("Doge",
6391 sol::constructors<Doge(), Doge(int)>(),
6392 "tailwag", &Doge::tailwag
6393 );
6394 lua.script(R"(
6395 function f (dog)
6396 if dog == nil then
6397 print('dog was nil!')
6398 return
6399 end
6400 print('dog wags its tail ' .. dog.tailwag .. ' times!')
6401 end
6402 )");
6403
6404 lua.script(R"(
6405 dog_lua = Doge.new()
6406 f(dog_lua)
6407 f(dog)
6408 f(dog_copy)
6409 f(dog_move)
6410 f(dog)
6411 f(dog_unique_ptr)
6412 f(dog_shared_ptr)
6413 f(nil)
6414 )");
6415
6416 cout << endl;
6417 return 0;
6418};
6419 int use_sol2(lua_State * L) {
6420 sol::state_view lua(L);
6421 lua.script("print('bark bark bark!')");
6422 return 0;
6423 }
6424
6425int main(int argc, char* argv[]) {
6426 state lua;// Lua состояние.
6427 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6428
6429 lua_pushcclosure(L, &use_sol2, 0);
6430 lua_setglobal(L, "use_sol2");
6431
6432 if (luaL_dostring(L, "use_sol2()")) {
6433 lua_error(L);
6434 return -1;
6435 }
6436
6437 cout << endl;
6438 return 0;
6439};
6440
6441 struct my_type {
6442 void stuff() {
6443 }
6444 };
6445int main(int argc, char* argv[]) {
6446 state lua;// Lua состояние.
6447 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6448
6449 /*
6450 // AAAHHH BAD
6451 // dangling pointer!
6452 lua["my_func"] = []() -> my_type* { return new my_type(); };
6453 // AAAHHH!
6454 lua.set("something", new my_type());
6455 // AAAAAAHHH!!!
6456 lua["something_else"] = new my_type();
6457 */
6458
6459 // :ok:
6460 lua["my_func0"] = []() -> unique_ptr<my_type> { return make_unique<my_type>(); };
6461
6462 // :ok:
6463 lua["my_func1"] = []() -> shared_ptr<my_type> { return make_shared<my_type>(); };
6464
6465 // :ok:
6466 lua["my_func2"] = []() -> my_type { return my_type(); };
6467
6468 // :ok:
6469 lua.set("something", unique_ptr<my_type>(new my_type()));
6470
6471 shared_ptr<my_type> my_shared = make_shared<my_type>();
6472 // :ok:
6473 lua.set("something_else", my_shared);
6474
6475 // :ok:
6476 auto my_unique = make_unique<my_type>();
6477 lua["other_thing"] = move(my_unique);
6478
6479 // :ok:
6480 lua["my_func5"] = []() -> my_type * {
6481 static my_type mt;
6482 return &mt;
6483 };
6484
6485 // THIS IS STILL BAD DON'T DO IT AAAHHH BAD
6486 // return a unique_ptr that's empty instead
6487 // or be explicit!
6488 lua["my_func6"] = []() -> my_type * { return nullptr; };
6489
6490 // :ok:
6491 lua["my_func7"] = []() -> nullptr_t { return nullptr; };
6492
6493 // :ok:
6494 lua["my_func8"] = []() -> unique_ptr<my_type> {
6495 // default-constructs as a nullptr,
6496 // gets pushed as nil to Lua
6497 return unique_ptr<my_type>();
6498 // same happens for shared_ptr
6499 };
6500
6501 // Acceptable, it will set 'something' to nil
6502 // (and delete it on next GC if there's no more references)
6503 lua.set("something", nullptr);
6504
6505 // Also fine
6506 lua["something_else"] = nullptr;
6507 cout << endl;
6508 return 0;
6509};
6510int main(int argc, char* argv[]) {
6511
6512 // 2 states, transferring function from 1 to another
6513 sol::state lua;
6514 sol::state lua2;
6515
6516 // we're not going to run the code on the first
6517 // state, so we only actually need
6518 // the base lib on the second state
6519 // (where we will run the serialized bytecode)
6520 lua2.open_libraries(sol::lib::base);
6521
6522 // load this code (but do not run)
6523 sol::load_result lr = lua.load("a = function (v) print(v) return v end");
6524 // check if it's sucessfully loaded
6525 c_assert(lr.valid());
6526
6527 // turn it into a function, then dump the bytecode
6528 sol::protected_function target = lr;
6529 sol::bytecode target_bc = target.dump();
6530
6531 // reload the byte code
6532 // in the SECOND state
6533 auto result2 = lua2.safe_script(target_bc.as_string_view(), sol::script_pass_on_error);
6534 // check if it was done properly
6535 c_assert(result2.valid());
6536
6537 // check in the second state if it was valid
6538 sol::protected_function pf = lua2["a"];
6539 int v = pf(25557);
6540 c_assert(v == 25557);
6541
6542 return 0;
6543};
6544
6545
6546int main(int argc, char* argv[]) {
6547 state lua;// Lua состояние.
6548 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6549 environment env(lua, sol::create, lua.globals());
6550 env["func"] = []() { return 42; };
6551
6552 environment env2(lua, sol::create, lua.globals());
6553 env2["func"] = []() { return 24; };
6554
6555 lua.script("function foo() print(func()) end", env);
6556 lua.script("function foo() print(func()) end", env2);
6557
6558 env["foo"](); // prints 42
6559 env2["foo"](); // prints 24
6560 cout << endl;
6561 return 0;
6562};
6563 string func_2(string text) {
6564 return "received: " + text;
6565 }
6566
6567 sol::variadic_results fallback(sol::this_state ts, sol::variadic_args args) {
6568 sol::variadic_results r;
6569 if (args.size() == 2) {
6570 r.push_back({ ts, sol::in_place, args.get<int>(0) + args.get<int>(1) });
6571 }
6572 else {
6573 r.push_back({ ts, sol::in_place, 52 });
6574 }
6575 return r;
6576 }
6577
6578int main(int argc, char* argv[]) {
6579 state lua;// Lua состояние.
6580 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6581 lua.set_function("f", sol::overload(
6582 func_1,
6583 func_2,
6584 fallback
6585 ));
6586
6587 lua.script("print(f(1))"); // func_1
6588 lua.script("print(f('hi'))"); // func_2
6589 lua.script("print(f(22, 11))"); // fallback
6590 lua.script("print(f({}))"); // fallback
6591
6592 return 0;
6593};
6594
6595
6596struct pup {
6597 int barks = 0;
6598
6599 void bark() {
6600 ++barks; // bark!
6601 }
6602
6603 bool is_cute() const {
6604 return true;
6605 }
6606};
6607
6608void ultra_bark(pup& p, int barks) {
6609 for (; barks-- > 0;) p.bark();
6610}
6611
6612void picky_bark(pup& p, string s) {
6613 if (s == "bark")
6614 p.bark();
6615}
6616
6617int main(int argc, char* argv[]) {
6618 state lua;// Lua состояние.
6619 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6620 lua.set_function("bark", sol::overload(
6621 ultra_bark,
6622 []() { return "the bark from nowhere"; }
6623 ));
6624
6625 lua.new_usertype<pup>("pup",
6626 // regular function
6627 "is_cute", &pup::is_cute,
6628 // overloaded function
6629 "bark", sol::overload(&pup::bark, &picky_bark)
6630 );
6631
6632 const auto& code = R"(
6633 barker = pup.new()
6634 print(barker:is_cute())
6635 barker:bark() -- calls member function pup::bark
6636 barker:bark("meow") -- picky_bark, no bark
6637 barker:bark("bark") -- picky_bark, bark
6638 bark(barker, 20) -- calls ultra_bark
6639 print(bark()) -- calls lambda which returns that string
6640 )";
6641
6642 lua.script(code);
6643
6644 pup& barker = lua["barker"];
6645 cout << barker.barks << endl;
6646// c_assert(barker.barks == 22);
6647
6648 return 0;
6649};
6650struct pup {
6651 int barks = 0;
6652
6653 void bark() {
6654 ++barks; // bark!
6655 }
6656
6657 bool is_cute() const {
6658 return true;
6659 }
6660};
6661
6662void ultra_bark(pup& p, int barks) {
6663 for (; barks-- > 0;) p.bark();
6664}
6665
6666void picky_bark(pup& p, string s) {
6667 if (s == "bark")
6668 p.bark();
6669}
6670struct some_class {
6671 int bark = 2012;
6672};
6673
6674sol::table open_mylib(sol::this_state s) {
6675 sol::state_view lua(s);
6676
6677 sol::table module = lua.create_table();
6678 module["func"] = []() {
6679 /* super cool function here */
6680 return 2;
6681 };
6682 // register a class too
6683 module.new_usertype<some_class>("some_class",
6684 "bark", &some_class::bark
6685 );
6686
6687 return module;
6688}
6689
6690int main(int argc, char* argv[]) {
6691 state lua;// Lua состояние.
6692 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6693// sol::c_call takes functions at the template level
6694 // and turns it into a lua_CFunction
6695 // alternatively, one can use sol::c_call<sol::wrap<callable_struct, callable_struct{}>> to make the call
6696 // if it's a constexpr struct
6697 lua.require("my_lib", sol::c_call<decltype(&open_mylib), &open_mylib>);
6698
6699 // run some code against your require'd library
6700 lua.safe_script(R"(
6701s = my_lib.some_class.new()
6702assert(my_lib.func() == 2)
6703s.bark = 20
6704)");
6705
6706 some_class& s = lua["s"];
6707 //c_assert(s.bark == 20);
6708 cout << "s.bark = " << s.bark << endl;
6709
6710 cout << endl;
6711
6712 return 0;
6713};
6714// Use raw function of form "int(lua_State*)"
6715// -- this is called a "raw C function",
6716// and matches the type for lua_CFunction
6717int LoadFileRequire(lua_State* L) {
6718 // use sol3 stack API to pull
6719 // "first argument"
6720 string path = sol::stack::get<string>(L, 1);
6721
6722 if (path == "a") {
6723 string script = R"(
6724 print("Hello from module land!")
6725 test = 123
6726 return "bananas"
6727 )";
6728 // load "module", but don't run it
6729 luaL_loadbuffer(L, script.data(), script.size(), path.c_str());
6730 // returning 1 object left on Lua stack:
6731 // a function that, when called, executes the script
6732 // (this is what lua_loadX/luaL_loadX functions return
6733 return 1;
6734 }
6735
6736 sol::stack::push(L, "This is not the module you're looking for!");
6737 return 1;
6738}
6739
6740int main(int argc, char* argv[]) {
6741 state lua;// Lua состояние.
6742 lua.open_libraries(lib::base, lib::package, lib::coroutine); // открыть доп.библиотеки.
6743// need base for print,
6744 // need package for package/searchers/require
6745 lua.open_libraries(sol::lib::base, sol::lib::package);
6746
6747 lua.clear_package_loaders();
6748 lua.add_package_loader(LoadFileRequire);
6749
6750 // this will call our function for
6751 // the searcher and it will succeed
6752 auto a_result = lua.safe_script(R"(
6753 local a = require("a")
6754 print(a)
6755 print(test)
6756 )", sol::script_pass_on_error);
6757// c_assert(a_result.valid());
6758 try {
6759 // this will always fail
6760 auto b_result = lua.safe_script(R"(
6761 local b = require("b")
6762 print(b)
6763 )", sol::script_throw_on_error);
6764 // this will not be executed because of the throw,
6765 // but it better be true regardless!
6766 // c_assert(!b_result.valid());
6767 }
6768 catch (const exception& ex) {
6769 // Whenever sol3 throws an exception from panic,
6770 // catch
6771 cout << "Something went wrong, as expected:\n" << ex.what() << endl;
6772 // and CRASH / exit the application
6773 return 0;
6774 }
6775
6776 // If we get here something went wrong...!
6777 return -1;
6778 return 0;
6779};
6780
6781
6782#include <sol.hpp>
6783#include <iostream>
6784#include <string>
6785#include <ctime>
6786#include <list>
6787#include <stack>
6788#include <memory>
6789#include <functional>
6790
6791
6792// a base class for scheduler tasks
6793class scheduler_task
6794{
6795public:
6796
6797 virtual ~scheduler_task() {}
6798 virtual bool is_complete() = 0;
6799};
6800
6801// callback_task is a convenience scheduler task
6802// that allows user to bind functions, function objects,
6803// lambdas, etc. as tasks to the scheduler
6804class callback_task : public scheduler_task
6805{
6806public:
6807 callback_task(function<bool()> callback)
6808 : m_callback(callback)
6809 {
6810 }
6811
6812 bool is_complete()
6813 {
6814 return m_callback();
6815 }
6816
6817private:
6818 function<bool()> m_callback;
6819};
6820
6821
6822namespace detail {
6823 struct scheduler_cothread;
6824 struct scheduler_thread_task;
6825 struct scheduler_task_list;
6826 struct thread_stack;
6827}
6828
6829class scheduler
6830{
6831public:
6832 scheduler(sol::state& state);
6833 virtual ~scheduler();
6834 void start(sol::string_view code);
6835 void run();
6836 void yield(shared_ptr<scheduler_task> task);
6837 int pending_tasks();
6838
6839 // yields a thread; copies the passed scheduler_task
6840 template <typename T>
6841 typename enable_if<is_base_of<scheduler_task, T>::value>::type
6842 yield(const T& task)
6843 {
6844 yield(make_shared<T>(task));
6845 }
6846
6847 // we also want to support plain function types as tasks
6848 void yield(bool(*callback)())
6849 {
6850 yield(make_shared<callback_task>(callback));
6851 }
6852
6853 // a convenience function for registering a yielding, optionally stateful, C++ function
6854 template <typename F>
6855 void register_function(string name, F&& f)
6856 {
6857 state[name] = sol::yielding(f);
6858 }
6859
6860private:
6861 sol::state& state;
6862 shared_ptr<detail::scheduler_cothread> m_current_thread;
6863 unique_ptr<detail::scheduler_task_list> m_tasks;
6864 unique_ptr<detail::thread_stack> m_thread_stack;
6865};
6866
6867
6868namespace detail {
6869
6870 struct scheduler_cothread {
6871 sol::thread thread;
6872 sol::coroutine coroutine;
6873 scheduler_cothread(sol::state& state, sol::string_view code) {
6874 thread = sol::thread::create(state);
6875 coroutine = thread.state().load(code);
6876 }
6877 };
6878
6879 struct scheduler_thread_task
6880 {
6881 shared_ptr<scheduler_cothread> thread;
6882 shared_ptr<scheduler_task> task;
6883 };
6884
6885 struct scheduler_task_list
6886 {
6887 list<scheduler_thread_task> tasks;
6888 };
6889
6890 struct thread_stack
6891 {
6892 stack<shared_ptr<scheduler_cothread>> threads;
6893 };
6894}
6895
6896scheduler::scheduler(sol::state& state)
6897 : state(state)
6898 , m_current_thread(0)
6899 , m_tasks(new detail::scheduler_task_list)
6900 , m_thread_stack(new detail::thread_stack)
6901{
6902}
6903
6904scheduler::~scheduler()
6905{
6906}
6907
6908
6909void scheduler::start(sol::string_view code)
6910{
6911 // set the current thread
6912 m_thread_stack->threads.push(make_shared<detail::scheduler_cothread>(state, code));
6913 m_current_thread = m_thread_stack->threads.top();
6914 // start the thread
6915 m_current_thread->coroutine();
6916 // reset current thread
6917 m_thread_stack->threads.pop();
6918 if (m_thread_stack->threads.empty())
6919 m_current_thread = nullptr;
6920 else
6921 m_current_thread = m_thread_stack->threads.top();
6922}
6923
6924void scheduler::run()
6925{
6926 // iterate through all pending tasks
6927 for (auto i = m_tasks->tasks.begin(); i != m_tasks->tasks.end();) {
6928 // if the thread is dead, remove it
6929 if (i->thread->coroutine.status() != sol::call_status::yielded) {
6930 i = m_tasks->tasks.erase(i);
6931 continue;
6932 }
6933
6934 // is this task complete?
6935 if (i->task->is_complete()) {
6936 // get the thread task
6937 detail::scheduler_thread_task thread_task = *i;
6938 // remove it from the pending list
6939 i = m_tasks->tasks.erase(i);
6940 // set the current thread
6941 m_thread_stack->threads.push(thread_task.thread);
6942 m_current_thread = thread_task.thread;
6943 // resume the thread
6944 thread_task.thread->coroutine();
6945 // reset current thread
6946 m_thread_stack->threads.pop();
6947 if (m_thread_stack->threads.empty())
6948 m_current_thread = nullptr;
6949 else
6950 m_current_thread = m_thread_stack->threads.top();
6951 }
6952 else {
6953 ++i;
6954 }
6955 }
6956}
6957
6958void scheduler::yield(shared_ptr<scheduler_task> task)
6959{
6960 detail::scheduler_thread_task thread_task;
6961 thread_task.thread = m_current_thread;
6962 thread_task.task = task;
6963 m_tasks->tasks.push_back(thread_task);
6964}
6965
6966int scheduler::pending_tasks()
6967{
6968 return m_tasks->tasks.size();
6969}
6970
6971
6972
6973class wait_task : public scheduler_task
6974{
6975public:
6976 wait_task(int secs) : m_secs(secs), m_start(time(0)) {}
6977 bool is_complete() { return ((time(0) - m_start) >= m_secs); }
6978private:
6979 int m_secs;
6980 time_t m_start;
6981};
6982
6983struct waits
6984{
6985 scheduler& m_scheduler;
6986 waits(scheduler& scheduler) : m_scheduler(scheduler) {}
6987 void operator()(int secs) const
6988 {
6989 cout << "C++ - Waiting for " << secs << " seconds" << endl;
6990 time_t start = time(0);
6991 return m_scheduler.yield<wait_task>(secs);
6992 }
6993};
6994
6995int func() {
6996 cout << "C++ - Inside f" << endl;
6997 return 24;
6998}
6999
7000void simple_test(sol::state& lua) {
7001 lua["f"] = sol::yielding(func);
7002
7003 sol::string_view code = R"(
7004 print('Lua - Before coroutine')
7005 f()
7006 print('Lua - After coroutine')
7007 )";
7008
7009 sol::coroutine co = lua.load(code);
7010 while (co) {
7011 cout << "C++ - Resuming coroutine" << endl;
7012 co();
7013 cout << "C++ - Coroutine status: " << sol::to_string(co.status()) << endl;
7014 }
7015}
7016
7017int main() {
7018 try {
7019 sol::state lua;
7020 lua.open_libraries(sol::lib::base, sol::lib::coroutine);
7021 cout << endl << "Simple test" << endl;
7022 simple_test(lua);
7023 cout << endl;
7024
7025
7026 cout << "Scheduler test" << endl;
7027 scheduler s(lua);
7028 s.register_function("wait", waits(s));
7029 s.register_function("show_text", [&s](string text) {
7030 cout << "C++ - Showing text: " << text << endl;
7031 return s.yield([]() { return true; });
7032 });
7033
7034 sol::string_view code = R"(
7035 print('Lua - Before first wait')
7036 wait(3)
7037 print('Lua - After wait, before show_text')
7038 show_text('hello')
7039 print('Lua - After show_text, before second wait')
7040 wait(5)
7041 print('Lua - After second wait')
7042 )";
7043
7044 sol::string_view code2 = R"(
7045 print('Lua - Before first wait 2')
7046 wait(5)
7047 print('Lua - After wait, before show_text 2')
7048 show_text('hi')
7049 print('Lua - After show_text, before second wait 2')
7050 wait(3)
7051 print('Lua - After second wait 2')
7052 )";
7053
7054 s.start(code);
7055 // s.start(code2) /* Uncomment to run concurrent threads */
7056 while (s.pending_tasks() > 0) {
7057 s.run();
7058 }
7059 }
7060 catch (exception& e) {
7061 cout << e.what() << endl;
7062 }
7063}
7064Потоки
7065
7066
7067int embeds_sol(lua_State* L) { // start using sol with a pre-existing system
7068 sol::state_view lua(L); // non-owning// runner = thread(foo);
7069 effil::Thread::exportAPI(lua);
7070 lua.open_libraries(sol::lib::base, sol::lib::package); // открыть доп.библиотеки.
7071 lua.script(LUA);
7072
7073std::thread t([=]() {
7074 lua["f"](0);
7075 });
7076t.detach();
7077 return 0; // все, что требуется для работы с необработанной функцией.
7078};
7079
7080int main(int argc, char* argv[]) {
7081 lua_State* L = luaL_newstate();
7082 luaL_openlibs(L);
7083 embeds_sol(L);
7084 sol::state lua;// Lua состояние.
7085 lua.open_libraries(sol::lib::base, sol::lib::package); // открыть доп.библиотеки.
7086 lua.script(LUA);// Сначала сохранить результат в переменной, затем вызвать.
7087 sol::function f = lua["f1"];
7088 f();
7089 cin.get();
7090 lua_close(L);
7091
7092 return 0;
7093};
7094
7095
7096lua_pushlightuserdata(L, L); /* отправить адрес памяти переменной в стек */
7097lua_pushstring(L, luafile); /* отправить значение в стек */
7098lua_settable(L, LUA_REGISTRYINDEX); /* уст ключа и значение таблице реестре. */
7099//lua_pushlightuserdata(L, L); /*отправить адрес, который является ключом в стек. */
7100//lua_gettable(L, LUA_REGISTRYINDEX); /* получить таблицу и значение ключа будет в -1 */
7101//char const* str1 = lua_tostring(L, -1);