egor230

sol3

Oct 10th, 2019
433
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 462.58 KB | None
  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>
  13. using namespace std;
  14. using namespace sol;
  15.  
  16. //Стек(англ.stack — стопка; читается стэк) — абстрактный тип данных, представляющий собой список элементов,
  17. //организованных по принципу LIFO(англ.last in — first out, «последний вошёл — первым вышел»)
  18. int 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.  
  30. const char* LUA = R"(
  31. print('Hello world!')
  32. )";
  33. int 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.  
  45. int 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.  
  106. int main(int argc, char* argv[]) {
  107. const 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.  
  138. const char* LUA = R"(
  139. print('Hello world!')
  140. )";
  141. int 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.  
  161. sol::state_view точно такой же sol::state, но он не управляет временем жизни lua_State*. Таким образом, вы получаете все вкусности, которые идут с sol::state без каких-либо последствий собственности.
  162. Sol не имеет компонентов инициализации, которые должны намеренно оставаться живыми в течение всей программы. Он полностью самодостаточен и использует сборщики мусора lua и различные методы реализации, не требующие состояния C ++. После того, как вы это сделаете, вам доступны все возможности sol , а затем и некоторые!
  163. sol::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.  
  170. int 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. };
  182. int 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. Еще пример.
  195. const char* LUA = R"(
  196. print("state view")
  197. )";
  198. int 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. };
  206. int 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.  
  224. config = {
  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.  
  237. int 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.  
  251. const char* LUA = R"(
  252. x= 20
  253. )";
  254. int 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. };
  265. const char* LUA = R"(
  266. x= 20
  267. )";
  268. int 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.  
  300. int 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.  
  327. int 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. };
  353. int 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. };
  371. const char* LUA = R"(
  372. config = {
  373. fullscreen = false,
  374. resolution = { x = 1024, y = 768 }
  375. }
  376. )";
  377. int 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.  
  404. int 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. };
  420. const char* LUA = R"(
  421. config = {
  422. fullscreen = 32
  423. }
  424. )";
  425. int 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.  
  450. int 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.  
  486. const 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. )";
  494. int 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.  
  520. int 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. Еще пример.
  539. int 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.  
  561. int 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. Еще пример.
  588. int 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.  
  611. Sol может регистрировать все виды функций. Многие из них показаны в быстром 'n' грязном, но здесь мы обсудим множество дополнительных способов регистрации функций в системе Lua, обернутой в sol.
  612.  
  613. Установка новой функции
  614. Имея функцию C ++, вы можете поместить ее в sol несколькими эквивалентными способами, работая аналогично тому, как работает установка переменных :
  615.  
  616. Регистрация функций C ++
  617. #include <sol/sol.hpp>
  618.  
  619. string 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.  
  625. int 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.  
  645. string my_function(int a, string b) {
  646. return b + string('D', a);
  647. }
  648.  
  649. int 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.  
  666. 2
  667. const char* LUA = R"(
  668. foo(1, 3)
  669. )";
  670. void foo(int a, int b) {
  671. cout << a+b << endl;
  672. }
  673.  
  674. int 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.  
  688. struct 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.  
  701. int 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.  
  736. int 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.  
  778. const char* LUA = R"(
  779. obj = t.class.new()
  780. n= obj:f()
  781. print(n)--24
  782. obj:g()
  783. n= obj:f()
  784. print(n)--25
  785. t.print_class(obj)
  786. )";
  787.  
  788. int 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.  
  812. const char* LUA = R"(
  813. obj = t.a.new()
  814. obj:show()
  815. t.print_class(obj)
  816. )";
  817.  
  818. int 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.  
  845. template <typename A, typename B>
  846. auto my_add( A a, B b ) {
  847. return a + b;
  848. }
  849. Вы должны указать все аргументы шаблона, чтобы связать и использовать его, вот так:
  850.  
  851. Регистрация инстанциации шаблона функции
  852. int 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.  
  871. 2.
  872. const char* LUA = R"(
  873. my_num = my_combine(1, 2)
  874. )";
  875. template <class t1, class t2>
  876. auto my_add(t1 a, t1 b) { return a + b; };
  877.  
  878. int 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 ++
  900. int 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.  
  917. int 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
  947. int 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.  
  969. const char* LUA = R"(
  970. function foo (a)
  971. return a + 5
  972. end
  973. )";
  974. int 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.  
  992. const char* LUA = R"(
  993. function foo ()
  994. print(223)
  995. end
  996. function f()
  997. print("func f")
  998. end
  999. )";
  1000. int 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
  1018. int 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.  
  1054. const 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. )";
  1067. int 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
  1095. int 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.  
  1113. const char* LUA = R"(
  1114. function f (a, b, c) return a, b, c end
  1115. )";
  1116. int 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.  
  1130. template<size_t I = 0, typename... Tp>
  1131. inline typename enable_if<I == sizeof...(Tp), void>::type
  1132. print(tuple<Tp...>& t)
  1133. { }
  1134.  
  1135. template<size_t I = 0, typename... Tp>
  1136. inline 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. }
  1142. const char* LUA = R"(
  1143. function f (a, b, c) return a+1, b+2, c+3 end
  1144. )";
  1145. int 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.  
  1162. int 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. Верни что-нибудь в Луа
  1193. sol::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.  
  1205. int 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.  
  1223. sol::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.  
  1235. int 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.  
  1257. const char* LUA = R"(
  1258. result3 = f(65)
  1259. )";
  1260.  
  1261. object 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.  
  1274. int 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.  
  1293. C ++ в Lua
  1294. Использование пользовательских типов («usertype» или просто «udt») просто с sol. Если вы не вызываете какие-либо переменные или функции-члены, вам даже не нужно «регистрировать» тип пользователя: просто пропустите его. Но если вам нужны переменные и функции для вашего пользовательского типа внутри Lua, вам нужно зарегистрировать его. Мы собираемся привести короткий пример, который включает в себя кучу информации о том, как работать с вещами.
  1295.  
  1296. Возьмите эту player структуру в C ++ в заголовочном файле:
  1297.  
  1298. player.hpp
  1299.  
  1300. #include <iostream>
  1301.  
  1302. struct player {
  1303. public:
  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.  
  1341. private:
  1342. int hp;
  1343. };
  1344. Это довольно минимальный класс, но мы не хотим переписывать это с помощью metatables в Lua. Мы хотим, чтобы это было частью Lua легко. Ниже приведен код Lua, который мы хотели бы иметь для правильной работы:
  1345.  
  1346. player_script.lua
  1347.  
  1348. p1 = player.new(2)
  1349.  
  1350. -- p2 is still here from being
  1351. -- set with lua["p2"] = player(0); below
  1352. local p2shoots = p2:shoot()
  1353. assert(not p2shoots)
  1354. -- had 0 ammo
  1355.  
  1356. -- set variable property setter
  1357. p1.hp = 545
  1358. -- get variable through property unqualified_getter
  1359. print(p1.hp)
  1360. assert(p1.hp == 545)
  1361.  
  1362. local did_shoot_1 = p1:shoot()
  1363. print(did_shoot_1)
  1364. print(p1.bullets)
  1365. local did_shoot_2 = p1:shoot()
  1366. print(did_shoot_2)
  1367. print(p1.bullets)
  1368. local did_shoot_3 = p1:shoot()
  1369. print(did_shoot_3)
  1370.  
  1371. -- can read
  1372. print(p1.bullets)
  1373. -- would error: is a readonly variable, cannot write
  1374. -- p1.bullets = 20
  1375.  
  1376. p1:boost()
  1377. -- call the function we define at runtime from a Lua script
  1378. p1:brake()
  1379.  
  1380.  
  1381. вариант 1.
  1382.  
  1383. struct player {
  1384. player() {this->hp = 10;}
  1385.  
  1386. void boost() { cout << hp << endl; }
  1387.  
  1388. private:
  1389. int hp;
  1390. };
  1391.  
  1392. const char* LUA = R"(
  1393. p1 = player.new()
  1394.  
  1395. p1:boost()
  1396.  
  1397. )";
  1398.  
  1399. int 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.
  1414. struct 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.  
  1424. const char* LUA = R"(
  1425. p1 = a.new()
  1426.  
  1427. p1:show()
  1428. p2 = a.new()
  1429.  
  1430. p2:show()
  1431.  
  1432. )";
  1433.  
  1434. int 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.  
  1451. main.cpp
  1452.  
  1453. #define SOL_ALL_SAFETIES_ON 1
  1454. #include <sol/sol.hpp>
  1455.  
  1456. #include "player.hpp"
  1457.  
  1458. #include <iostream>
  1459.  
  1460. int 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.  
  1499. prelude_script.lua
  1500. function player:brake ()
  1501. self.speed = 0
  1502. print("we hit the brakes!")
  1503. end
  1504. Теперь этот сценарий должен работать нормально, и вы можете наблюдать и играть со значениями. Еще больше вещей, которые вы можете сделать , описано в другом месте, например, функции инициализатора (поддержка частных конструкторов / деструкторов), «статические» функции, которые можно вызывать , и перегруженные функции-члены. Вы можете даже связать глобальные переменные (даже по ссылке с ) с помощью. Есть много чего попробовать!
  1505.  
  1506. name.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.  
  1518. object_lifetime.cpp
  1519.  
  1520. #define SOL_ALL_SAFETIES_ON 1
  1521. #include <sol/sol.hpp>
  1522.  
  1523. #include <string>
  1524. #include <iostream>
  1525.  
  1526. int 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.
  1559. int 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. владение указателем.
  1606. Sol не будет владеть необработанными указателями: необработанные указатели не владеют ничем. sol не будет удалять необработанные указатели, потому что они не имеют (и не должны) ничего:
  1607.  
  1608. pointer_lifetime.cpp
  1609. #define SOL_ALL_SAFETIES_ON 1
  1610. #include <sol/sol.hpp>
  1611.  
  1612. struct my_type {
  1613. void stuff() {
  1614. }
  1615. };
  1616.  
  1617. int 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.  
  1639. struct my_type {
  1640. void stuff() {
  1641. }
  1642. };
  1643.  
  1644. int 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.  
  1665. struct my_type {
  1666. void stuff() {
  1667. }
  1668. };
  1669.  
  1670. int 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.  
  1680. Sol может обнаружить 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.  
  1686. struct my_type {
  1687. void stuff() {
  1688. }
  1689. };
  1690.  
  1691. int 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.  
  1736. struct two_things {
  1737. int a;
  1738. bool b;
  1739. };
  1740.  
  1741. template <typename Handler>
  1742. bool 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.  
  1754. two_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.  
  1766. int 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.  
  1775. int 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
  1816. struct two_things {
  1817. int a;
  1818. bool b;
  1819. };
  1820.  
  1821. template <typename Handler>
  1822. bool 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.  
  1829. two_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.  
  1837. int 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.  
  1844. int 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.  
  1865. struct t {
  1866. int a;
  1867. };
  1868.  
  1869. template <typename Handler>
  1870. bool 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.  
  1879. t 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. };
  1885. int 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.  
  1890. int 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 ++.
  1942. Mac 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 здесь .
  1962. Lua - это прежде всего 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. поддерживаемые компиляторы
  1978. GCC 7.x теперь отсутствует вместе с Visual Studio 2018. Это означает, что Sol-версия v2.20.1 - это текущая версия кода, предназначенная для более старых компиляторов, не перечисленных ниже. Более новый код будет нацелен на работу со следующими компиляторами и использование их возможностей, возможно, с использованием любых возможностей C ++ 17, предоставляемых компиляторами и стандартными библиотеками, связанными с ними по умолчанию.
  1979. v2.20.1 поддерживает:
  1980. VC ++
  1981. Visual Studio 2018
  1982. Visual Studio 2015 (последние обновления)
  1983. GCC (включает MinGW)
  1984. V7.x
  1985. v6.x
  1986. v5.x
  1987. v4.8 +
  1988. лязг
  1989. v4.x
  1990. v3.9.x
  1991. v3.8.x
  1992. v3.7.x
  1993. v3.6.x
  1994. Примечание: это относится и к Apple Clang в XCode, но этот компилятор также имеет свои недостатки и проблемы
  1995. Это не значит, что мы немедленно отказываемся от старых компиляторов. Мы обновим эту страницу, так как соответствующие исправления перенесены в выпуски v2.xx. Помните, что sol3 является полнофункциональным: больше ничего мы не можем добавить в библиотеку на данный момент с поддержкой компилятора C ++ 11 / C ++ 14, так что ваш код будет покрыт еще долго.
  1996. Новые функции будут нацелены на следующие компиляторы:
  1997. VC ++
  1998. Visual Studio vNext
  1999. Visual Studio 2018
  2000. GCC (включает MinGW)
  2001. v8.x
  2002. V7.x
  2003. лязг
  2004. V7.x
  2005. v6.x
  2006. v5.x
  2007. v4.x
  2008. v3.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. Мы поддерживаем:
  2017. Lua 5.3+
  2018. Lua 5.2
  2019. Lua 5.1
  2020. LuaJIT 2.0.x +
  2021. LuaJIT 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. Ленивая оценка для вложенных / цепочек запросов
  2043. table["a"]["b"]["c"] = 24;
  2044. Неявное преобразование в типы, которые вы хотите
  2045. double b = table["computed_value"];
  2046. получение поддержки: пометьте функцию, чей возврат должен привести к сопрограмме
  2047. Дополнительная поддержка: установка значений, получение значений нескольких (разных) типов
  2048. Ленивая оценка для вложенных / цепочек запросов
  2049. optional<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 ++
  2066. my_class& a = table["a"]; my_class* a_ptr = table["a"];
  2067. Если вам нужна копия, просто используйте семантику значений и получите копии:
  2068. my_class a = table["a"];
  2069. Поддержка потоков / сопрограмм
  2070. Используйте, возобновляйте и играйте с сопрограммами, как обычные функции
  2071. Получить и использовать их даже в отдельном потоке Lua
  2072. Мониторинг статуса и проверка ошибок
  2073. Дополнительно: настраивается и расширяется под ваши собственные типы, если вы переопределяете определения структуры шаблона getter / pusher / checker .
  2074. Feature Matrix ™
  2075. Приведенная ниже таблица характеристик проверяет наличие чего-либо. Это, однако, фактически не учитывает трудоемкий синтаксис.
  2076. ✔ полная поддержка: работает так, как вы ожидаете (оператор [] для таблиц и т. Д.)
  2077. ~ частичная поддержка / поддержка wonky: это означает, что она либо поддерживается другим способом (не с желаемым синтаксисом, серьезными предостережениями и т. д.). Иногда означает отказ от использования простого C API (в какой момент, в чем смысл абстракции?).
  2078. Support нет поддержки: функция не работает или, если она есть, она ДЕЙСТВИТЕЛЬНО не подходит
  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.
  2087. udts - функции-члены: функции-члены C ++ для типа, обычно вызываемые my_object:foo(1)или похожие в Lua.
  2088. udts - табличные переменные: переменные / свойства члена C ++, управляемые и в Luamy_object.var = 24
  2089. Функция привязки: поддержка привязки всех типов функций. Лямбды, функции-члены, свободные функции, в разных контекстах и т. Д.
  2090. защищенная функция: использование lua_pcallдля вызова функции, которая предлагает обработку ошибок и прыжок на батуте (а также возможность отказаться от этого поведения)
  2091. multi-return: возвращение нескольких значений из и в Lua (обычно через tuple<...>или каким-либо другим способом)
  2092. Вариантный / вариантный аргумент: возможность принимать «что угодно» от Lua и даже возвращать «что угодно» Lua ( objectабстракция, вариационные аргументы и т. д.)
  2093. наследование: допускает некоторую степень подтипирования или наследования классов / пользовательских данных от Lua - это обычно означает, что вы можете извлечь базовый указатель из Lua, даже если вы передадите библиотеке производный указатель
  2094. перегрузка: способность вызывать перегруженные функции, сопоставленные по арности или типу (тогда lua вызывает другую функцию ).foo( 1 )foo("bark" )
  2095. Lua 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) ~ ✔ ✔ ✔ ✔ ✔ ~ ✔ ✔ ✔ ✔ ✔ ✔
  2105. udts: функции-члены ~ ✔ ✔ ✔ ✔ ✔ ~ ✔ ✔ ✔ ✔ ✔ ✔
  2106. udts: переменные таблицы ~ ~ ~ ~ ~ ✔ ~ ~ ~ ✗ ✔ ✗ ~
  2107. абстракции стека ~ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ~ ✗ ~ ✔
  2108. Lua Callables из C (++) ~ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ~
  2109. привязка функции ~ ✔ ✔ ✔ ✔ ✔ ~ ~ ✔ ~ ~ ~ ✔
  2110. защищенный вызов ~ ✗ ~ ~ ~ ✔ ~ ✔ ~ ~ ~ ~ ~
  2111. мульти-возврат ~ ✗ ✔ ✔ ✔ ✔ ~ ✔ ✔ ~ ✔ ~ ✗
  2112. вариационный / вариантный аргумент ~ ✔ ✔ ✔ ✔ ✔ ~ ✔ ✔ ~ ~ ~ ✗
  2113. наследование ~ ✔ ✔ ✔ ✔ ✔ ~ ~ ✔ ~ ✔ ~ ✗
  2114. перегрузка ~ ✗ ✔ ✗ ✗ ✔ ✗ ✗ ✔ ✔ ✔ ✗ ✗
  2115. Луа нить ~ ✗ ~ ✗ ✗ ✔ ✔ ✗ ✔ ✗ ✗ ✔ ✗
  2116. окружающая среда ✗ ✗ ✗ ✗ ✗ ✔ ✗ ✗ ✗ ✗ ✗ ✗ ✗
  2117. сопрограммы ~ ✗ ~ ✔ ✔ ✔ ✗ ✗ ✔ ✗ ✗ ✔ ✗
  2118. дающие функции C ++ ~ ✔ ✔ ✔ ~ ✔ ~ ✗ ✔ ✗ ~ ✔ ~
  2119. поддержка no-rtti ✔ ✗ ✔ ✗ ✗ ✔ ✔ ✗ ✔ ✔ ~ ✔ ✔
  2120. поддержка без исключений ✔ ✗ ✔ ~ ✗ ✔ ✔ ✗ ✔ ✔ ~ ✔ ✔
  2121. Lua 5.1 ✔ ✔ ✔ ✔ ✗ ✔ ✔ ✔ ✔ ✔ ✔ ✗ ✔
  2122. Lua 5.2 ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
  2123. Lua 5.3 ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
  2124. LuaJIT ✔ ✔ ✔ ✔ ~ ✔ ✔ ✔ ✔ ✔ ✔ ✗ ✔
  2125. распределение компилировать заголовок и то и другое компилировать заголовок заголовок компилировать компилировать заголовок компилировать генерироваться компилировать заголовок
  2126. замечания по реализации
  2127. Обычный C -
  2128. Очевидно, что вы можете делать все что угодно с Plain C, но прилагаемые усилия являются астрономическими по сравнению с тем, что предлагают другие оболочки, библиотеки и фреймворки.
  2129. Не очень хорошо масштабируется (с точки зрения простоты использования разработчиком)
  2130. Компиляция (или использование менеджера пакетов), очевидно, необходима для вашей платформы и требует использования ЛЮБЫХ из этих библиотек, но это нормально, потому что все библиотеки в любом случае нуждаются в некоторой версии Lua, так что у вас всегда есть это!
  2131. кагуя -
  2132. Табличные переменные / переменные-члены автоматически превращаются в набор и получениеobj:x( value )obj:x()
  2133. Имеет дополнительную поддержку
  2134. Вдохновленная поддержка сопрограмм для sol
  2135. Автор библиотеки (саторен) хороший парень!
  2136. C ++ 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. Заслуживает много любви!
  2146. lua-intf -
  2147. Может быть как заголовочным, так и скомпилированным
  2148. Имеет дополнительную поддержку
  2149. C ++ 11
  2150. Регистрация на основе макросов (странный псевдо-язык)
  2151. Довольно быстро в большинстве случаев
  2152. Регистрация классов / «модулей» при использовании кода на C ++ чрезвычайно многословна
  2153. Чтобы связать поиски в цепочку, нужно склеить ключи (например, "mykey.mykey2") при operator[]поиске (например, вы не можете их произвольно вложить, вы должны предварительно составить правильную строку поиска) (с треском проваливается для поиска не в строке! ).
  2154. Не так уж и плохо!
  2155. Селена -
  2156. Табличные переменные / переменные-члены автоматически превращаются в набор и получениеobj:set_x( value )obj:x()
  2157. Регистрация классов / «модулей» с использованием кода C ++ очень многословна, похожа на стиль lua-intf
  2158. Большую часть времени ест дерьмо, когда дело доходит до производительности (см. Тесты )
  2159. Многие пользователи (посты в блогах и т. Д. Сделали его популярным), но репозиторий довольно застойный ...
  2160. Luawrapper -
  2161. Принимает подход написания и чтения таблиц с использованием readVariableи writeVariableфункций
  2162. C ++ 11, без макросов!
  2163. Интерфейс может быть неуклюжим (нет табличных структур данных: большинство вещей идет, хотя readVariable/ writeVariable)
  2164. Внутренние ошибки компилятора в Visual Studio 2015 - отправлен PR, чтобы исправить это, надеюсь, он будет поднят
  2165. SWIG (3.0) -
  2166. Очень всеобъемлющий для привязки понятий C ++ (классы, переменные и т. Д.) К Lua
  2167. Помогает буквально ни с чем другим (таблицы, потоки, абстракции стека и т. Д.)
  2168. Не очень хорошая, полнофункциональная библиотека ...
  2169. Требуется этап предварительной обработки (но это не… УЖАСНО сложный этап предварительной обработки); некоторый пример написания дополнительных классов, которые вы уже объявили
  2170. luacppinterface -
  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, который можно использовать с легкостью. В КОНЦЕ КОНЦОВ
  2189. C ++ 11-иш в некоторых отношениях
  2190. Грустное лицо, благодаря способу регистрации пользовательских данных
  2191. SLB3 -
  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.  
  2215. compatibility.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.  
  2224. template <typename T>
  2225. struct user;
  2226.  
  2227. template <typename T>
  2228. struct light;
  2229. sol::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.  
  2237. namespace stack
  2238. Если вы обнаружите, что абстракции более высокого уровня не соответствуют вашим потребностям, вы, возможно, захотите углубиться в stack пространство имен, чтобы попытаться получить больше от sol. stack.hpp а stack пространство имен определяет несколько утилит для работы с Lua, включая утилиты push / popping, геттеры, средства проверки типов, помощники вызовов Lua и многое другое. Это пространство имен не документировано полностью, так как большая часть его интерфейса является ртутной и может меняться между выпусками, либо сильно повышать производительность, либо улучшать sol api .
  2239.  
  2240. Работу на этом уровне стека можно улучшить, если понять, как работает стек Lua в целом, а затем дополнить его объектами и предметами.
  2241.  
  2242. Однако есть несколько точек настройки ADL, которые вы можете использовать для своих целей, и несколько потенциально полезных функций. Это может помочь, если вы пытаетесь уменьшить объем кода, который вам нужно написать, или если вы хотите, чтобы ваши типы по-разному вели себя в стеке sol. Обратите внимание, что переопределение значений по умолчанию может привести к отказу от многих гарантий безопасности, которые предоставляет sol: поэтому изменяйте точки расширения по своему усмотрению.
  2243.  
  2244. структуры
  2245. структура: запись
  2246. struct 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. структура: зонд
  2259. struct 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
  2270. template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
  2271. inline 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. функция: получить
  2275. template <typename T>
  2276. auto get( lua_State* L, int index = -1 )
  2277. template <typename T>
  2278. auto 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. функция: проверить
  2284. template <typename T>
  2285. bool check( lua_State* L, int index = -1 )
  2286.  
  2287. template <typename T, typename Handler>
  2288. bool check( lua_State* L, int index, Handler&& handler )
  2289.  
  2290. template <typename T, typename Handler>
  2291. bool 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
  2295. template <typename T>
  2296. auto get_usertype( lua_State* L, int index = -1 )
  2297. template <typename T>
  2298. auto get_usertype( lua_State* L, int index, record& tracking )
  2299. Непосредственно пытается повторно получить тип, Tиспользуя механизмы пользовательского типа sol3. Аналогично обычному getдля определенного пользователем типа. Полезно, когда вам нужно получить доступ к механизму получения пользовательских типов в sol3 и в то же время обеспечить собственную настройку .
  2300.  
  2301. функция: check_usertype
  2302. template <typename T>
  2303. bool check_usertype( lua_State* L, int index = -1 )
  2304.  
  2305. template <typename T, typename Handler>
  2306. bool check_usertype( lua_State* L, int index, Handler&& handler )
  2307.  
  2308. template <typename T, typename Handler>
  2309. bool check_usertype( lua_State* L, int index, Handler&& handler, record& tracking )
  2310. Проверяет, имеет ли объект at indexтип Tи сохраняется ли он как пользовательский тип sol3. Полезно, когда вам нужно получить доступ к механизму проверки пользовательских типов sol3, в то же время предоставляя свои собственные настройки .
  2311.  
  2312. функция: check_get
  2313. template <typename T>
  2314. auto check_get( lua_State* L, int index = -1 )
  2315. template <typename T, typename Handler>
  2316. auto 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
  2321. template <typename T, typename... Args>
  2322. int push( lua_State* L, T&& item, Args&&... args )
  2323.  
  2324. // push T that is explicitly specified, pass args... through to extension point
  2325. template <typename T, typename Arg, typename... Args>
  2326. int push( lua_State* L, Arg&& arg, Args&&... args )
  2327.  
  2328. // recursively call the the above "push" with T inferred, one for each argument
  2329. template <typename... Args>
  2330. int 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
  2335. template <typename T, typename... Args>
  2336. int push_reference( lua_State* L, T&& item, Args&&... args )
  2337.  
  2338. // push T that is explicitly specified, pass args... through to extension point
  2339. template <typename T, typename Arg, typename... Args>
  2340. int push_reference( lua_State* L, Arg&& arg, Args&&... args )
  2341.  
  2342. // recursively call the the above "push" with T inferred, one for each argument
  2343. template <typename... Args>
  2344. int multi_push_reference( lua_State* L, Args&&... args )
  2345. Эти функции ведут себя аналогично приведенным выше, но они проверяют определенные критерии и вместо этого пытаются выдвинуть ссылку, а не принудительно копировать копию, если это необходимо. Используйте его осторожно, так как sol3 использует это главным образом как возврат из функций и переменных пользовательского типа, чтобы сохранить семантику цепочки / переменной от этого объекта класса. Его внутренние компоненты обновляются в соответствии с потребностями sol3, и, хотя он, как правило, делает «правильные вещи» и его не нужно менять какое-то время, sol3 оставляет за собой право изменять свои внутренние механизмы обнаружения в соответствии с потребностями своих пользователей в любое время, как правило, без нарушения обратной совместимости и ожиданий, но не совсем гарантировано.
  2346.  
  2347. функция: поп
  2348. template <typename... Args>
  2349. auto pop( lua_State* L );
  2350. Выталкивает объект из стека Удалит фиксированное количество объектов из стека, как правило, определяется sol::lua_size<T>чертами предоставленных аргументов. Обычно это функция простоты, используемая для удобства.
  2351.  
  2352. функция: верх
  2353. int top( lua_State* L );
  2354. Возвращает количество значений в стеке.
  2355.  
  2356. функция: set_field
  2357. template <bool global = false, typename Key, typename Value>
  2358. void set_field( lua_State* L, Key&& k, Value&& v );
  2359.  
  2360. template <bool global = false, typename Key, typename Value>
  2361. void set_field( lua_State* L, Key&& k, Value&& v, int objectindex);
  2362. Устанавливает поле, на которое ссылается ключ, kна заданное значение v, помещая ключ в стек, помещая значение в стек, а затем выполняя эквивалент lua_setfieldобъекта для данного значения objectindex. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
  2363.  
  2364. функция: get_field
  2365. template <bool global = false, typename Key>
  2366. void get_field( lua_State* L, Key&& k [, int objectindex] );
  2367. Получает поле, на которое ссылается ключ k, путем нажатия ключа на стек и затем выполнения эквивалента lua_getfield. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
  2368.  
  2369. Эта функция оставляет полученное значение в стеке.
  2370.  
  2371. функция: probe_get_field
  2372. template <bool global = false, typename Key>
  2373. probe 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
  2384. MyType 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
  2395. int 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
  2405. template <typename Handler>
  2406. bool 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
  2423. template <typename T, typename Handler>
  2424. bool 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
  2439. template <typename T>
  2440. pair<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 ++
  2460. template <typename... Args, typename F>
  2461. constexpr auto resolve( F f );
  2462. resolveэто функция, которая предназначена для того, чтобы помочь пользователям выбрать одну функцию из группы перегруженных функций в C ++. Он работает как для членских, так и для свободных функций. Вы можете использовать его для выбора перегрузок, указав сигнатуру в качестве первого аргумента шаблона. Дан набор перегруженных функций:
  2463.  
  2464. int overloaded(int x);
  2465. int overloaded(int x, int y);
  2466. int overloaded(int x, int y, int z);
  2467.  
  2468. struct 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.  
  2476. auto one_argument_func = resolve<int(int)>( overloaded );
  2477. auto two_argument_func = resolve<int(int, int)>( overloaded );
  2478. auto three_argument_func = resolve<int(int, int, int)>( overloaded );
  2479. auto member_three_argument_func = resolve<int(int, int, int)>( &thing::overloaded );
  2480. auto member_zero_argument_const_func = resolve<int() const>( &thing::overloaded );
  2481. Это важно отметить , что constпомещается в конце для того, когда вы хотите константные перегрузки. Вы получите ошибки компилятора, если вы не конкретизируете и не устраните неоднозначность для функций-членов const. Это разрешение также становится полезным при установке функций для таблицы или state_view :
  2482.  
  2483.  
  2484. sol::state lua;
  2485.  
  2486. lua.set_function("a", resolve<int(int)>( overloaded ) );
  2487. lua.set_function("b", resolve<int(int, int)>( overloaded ));
  2488. lua.set_function("c", resolve<int(int, int, int)>( overloaded ));
  2489. Его также можно использовать с sol :: c_call :
  2490.  
  2491.  
  2492. sol::state lua;
  2493.  
  2494. auto f = sol::c_call<
  2495. decltype(sol::resolve<int(int, int)>(&overloaded)),
  2496. sol::resolve<int(int, int)>(&overloaded)
  2497. >;
  2498. lua.set_function("f", f);
  2499.  
  2500. lua.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.  
  2505. c_call
  2506. шаблонный тип для передачи функций через шаблоны
  2507.  
  2508. template <typename Function, Function f>
  2509. int c_call (lua_State* L);
  2510.  
  2511. template <typename... Functions>
  2512. int 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.  
  2530. int f1(int) { return 32; }
  2531.  
  2532. int f2(int, int) { return 1; }
  2533.  
  2534. struct fer {
  2535. double f3(int, int) {
  2536. return 2.5;
  2537. }
  2538. };
  2539.  
  2540.  
  2541. int 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 :: Содержание :: разрешение »
  2576. as_function
  2577. убедитесь, что объект выдвинут как функция
  2578.  
  2579. template <typename Sig = sol::function_sig<>, typename... Args>
  2580. function_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.  
  2588. int 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.  
  2613. int 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.  
  2642. template <typename T>
  2643. auto readonly( T&& value );
  2644. Цель только для чтения - защитить набор переменных для типа пользователя или функции. Просто оберните его вокруг переменной-члена, например, в соответствующем месте, чтобы использовать его. Если кто-то попытается установить его, он ошибется своим кодом.sol::readonly( &my_class::my_member_variable )
  2645.  
  2646. sol::readonlyЭто особенно важно, когда вы работаете с типами, которые не имеют конструктора копирования. Lua не понимает семантику перемещения, и поэтому для установщиков пользовательских типов требуется конструктор копирования C ++. Контейнеры как переменные-члены, которые содержат типы, которые не являются копируемыми, но могут быть перемещены - например, vector<my_move_only_type>среди других - также могут ошибочно утверждать, что они являются копируемыми, но терпят неудачу с ошибками компилятора. Если ваш тип не соответствует определению контейнера как подлежащего копированию или просто не подлежит копированию в целом, и это переменная-член, пожалуйста, используйте sol::readonly.
  2647.  
  2648. Если вы хотите создать таблицу только для чтения, вам нужно пройти через сложную песню и танец, переопределив __indexметаметод. Вот полный пример того, как это сделать, используя sol:
  2649.  
  2650. read_only.cpp
  2651.  
  2652. #define SOL_ALL_SAFETIES_ON 1
  2653. #include <sol/sol.hpp>
  2654.  
  2655. #include <iostream>
  2656.  
  2657. struct object {
  2658. void my_func() {
  2659. cout << "hello\n";
  2660. }
  2661. };
  2662.  
  2663. int deny(lua_State* L) {
  2664. return luaL_error(L, "HAH! Deniiiiied!");
  2665. }
  2666.  
  2667. int 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"(
  2691. print(object.my_func)
  2692. object["my_func"] = 24
  2693. print(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.  
  2706. sol::policiesэто продвинутая функция низкоуровневой модификации, позволяющая вам использовать преимущества абстракций sol3 перед применением ваших собственных стековых модификаций в последний момент. Они охватывают ту же функциональность, что и типы luabind «return reference» и «зависимости» . Для вашего использования определены несколько предварительно настроенных политик:
  2707.  
  2708. политика использование модификация
  2709. sol::returns_self sol::policies( some_function, sol::returns_self() )
  2710. принимает аргумент в стеке с индексом 1 ( selfв вызовах функций-членов и лямбда-выражениях, которые вначале принимают определенные пользовательские данные) и делает его возвращаемым значением
  2711. вместо того, чтобы создавать новые пользовательские данные, которые ссылаются на ту же память C ++, он копирует пользовательские данные, подобно записи просто увеличивает счетчик ссылокobj2 = obj1
  2712. экономит пространство памяти поверх сохранения оригинальной памяти
  2713. sol::returns_self_with<int...> sol::policies( some_function, sol::returns_self_with<2, 3>() )
  2714. то же самое, что и выше, с предупреждением, selfкоторое возвращается, в то же время помещая зависимости вself
  2715. может поддерживать внешние зависимости
  2716. sol::self_dependency sol::policies( some_function, sol::self_dependency() );
  2717. это делает значение, возвращаемое связываемым объектом, зависимым от selfаргумента
  2718. полезно для возврата ссылки на переменную-член и поддержания живого родительского класса этой переменной-члена
  2719. sol::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.  
  2735. template <typename T>
  2736. auto protect( T&& value );
  2737. sol::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.  
  2744. int 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.  
  2778. struct test {
  2779. static int number;
  2780. };
  2781. int test::number = 25;
  2782.  
  2783.  
  2784. int 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.  
  2824. template <typename F>
  2825. yield_wrapper<F> yielding( F&& f )
  2826. sol::yieldingполезен для вызова функций C ++, которые должны быть преобразованы в сопрограмму Lua. Это обертка вокруг одного аргумента, который, как ожидается, будет связан как функция. Вы можете передавать его везде, где может быть связана обычная функция, за исключением определений пользовательских типов .
  2827.  
  2828. сопрограмма
  2829. Возобновляемые / уступающие функции от Lua
  2830.  
  2831. A coroutine- это ссылка на функцию в Lua, которую можно вызывать несколько раз, чтобы получить конкретный результат. Он запускается в lua_State, который использовался для его создания (см. Поток для примера того, как получить сопрограмму, которая работает в потоке, отдельном от вашего обычного «основного» lua_State ).
  2832.  
  2833. Coroutine Объект полностью аналогичен protected_function объекта, с дополнительными функциями - членами , чтобы проверить , если сопрограмма дал ( call_status :: выданное ) , и, таким образом , снова работоспособной, была ли она завершена ( call_status :: ОК ) и , следовательно , не может дать больше значения, или произошла ошибка (см. коды ошибок status () и call_status ).
  2834.  
  2835. Например, вы можете работать с сопрограммой следующим образом:
  2836.  
  2837. co.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.  
  2848. main.cpp
  2849. sol::state lua;
  2850. lua.open_libraries(sol::lib::base, sol::lib::coroutine);
  2851. lua.script_file("co.lua");
  2852. sol::coroutine cr = lua["loop"];
  2853.  
  2854. for (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.  
  2865. main_with_thread.cpp
  2866. sol::state lua;
  2867. lua.open_libraries(sol::lib::base, sol::lib::coroutine);
  2868. lua.script_file("co.lua");
  2869. sol::thread runner = sol::thread::create(lua.lua_state());
  2870. sol::state_view runnerstate = runner.state();
  2871. sol::coroutine cr = runnerstate["loop"];
  2872.  
  2873. for (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.
  2879. const 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.  
  2891. int 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. функция: конструктор
  2922. coroutine(lua_State* L, int index = -1);
  2923. Хватает сопрограмму по указанному индексу с учетом lua_State*.
  2924.  
  2925. возвращение статуса сопрограммы
  2926. call_status status() const noexcept;
  2927. Возвращает статус сопрограммы.
  2928.  
  2929. проверяет на ошибку
  2930. bool error() const noexcept;
  2931. Проверяет, произошла ли ошибка при запуске сопрограммы.
  2932.  
  2933. выполняемый и явный оператор bool
  2934. bool runnable () const noexcept;
  2935. explicit operator bool() const noexcept;
  2936. Эти функции позволяют проверить, можно ли еще вызывать сопрограмму (имеет больше значений для выдачи и не имеет ошибок). Если у вас есть объект сопрограммы , вы можете проверить или сделать .coroutine my_co = /*...*/runnable()if ( my_co ) { /* use coroutine */ }
  2937.  
  2938. вызывая сопрограмму
  2939. template<typename... Args>
  2940. protected_function_result operator()( Args&&... args );
  2941.  
  2942. template<typename... Ret, typename... Args>
  2943. decltype(auto) call( Args&&... args );
  2944.  
  2945. template<typename... Ret, typename... Args>
  2946. decltype(auto) operator()( types<Ret...>, Args&&... args );
  2947. Вызывает сопрограмму. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Затем проверьте дополнительную информацию об успешном выполнении или просто проверьте объект сопрограммы в сообщении ifs, как показано выше .my_co(sol::types<int, string>, ...)status()
  2948.  
  2949. защищенная
  2950. Вызовы функций Lua, которые перехватывают ошибки и обеспечивают обработку ошибок
  2951.  
  2952. class protected_function : public reference;
  2953. typedef 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.  
  2983. int 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
  3047. sol::protected_function problematicwoof(lua["woof"], lua["got_problems"]);
  3048.  
  3049. // dangerous if things go wrong!
  3050. double value = problematicwoof(19);
  3051. Наконец, важно отметить, что вы можете установить обработчик по умолчанию. Функция описана ниже: пожалуйста, используйте ее, чтобы избежать необходимости постоянно устанавливать обработчики ошибок:
  3052.  
  3053. // sets got_problems as the default
  3054. // handler for all protected_function errors
  3055. sol::protected_function::set_default_handler(lua["got_problems"]);
  3056.  
  3057. sol::protected_function problematicwoof = lua["woof"];
  3058. sol::protected_function problematicwoofers = lua["woofers"];
  3059.  
  3060. double value = problematicwoof(19);
  3061. double value2 = problematicwoof(9);
  3062. члены
  3063. конструктор: protected_function
  3064. template <typename T>
  3065. protected_function( T&& func, reference handler = sol::protected_function::get_default_handler() );
  3066. protected_function( lua_State* L, int index = -1, reference handler = sol::protected_function::get_default_handler() );
  3067. Создаёт protected_function. Используйте версию с двумя аргументами, чтобы легче передавать пользовательскую функцию обработки ошибок. Вы также можете установить переменную-член error_handler после создания позже. protected_functionвсегда будет использовать последний обработчик ошибок, установленный для переменной, который является либо тем, что вы передали ей, либо значением по умолчанию во время создания .
  3068.  
  3069. функция: вызов оператора / вызов защищенной функции
  3070. template<typename... Args>
  3071. protected_function_result operator()( Args&&... args );
  3072.  
  3073. template<typename... Ret, typename... Args>
  3074. decltype(auto) call( Args&&... args );
  3075.  
  3076. template<typename... Ret, typename... Args>
  3077. decltype(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. обработчики по умолчанию
  3085. static const reference& get_default_handler ();
  3086. static void set_default_handler( reference& ref );
  3087. Получите и установите объект Lua, который используется в качестве обработчика ошибок по умолчанию. По умолчанию используется обработчик ошибок no-ref. Вы можете изменить это, позвонив или подобный: все, что производит ссылку, должно быть хорошо.protected_function::set_default_handler( lua["my_handler"] );
  3088.  
  3089. переменная: обработчик
  3090. reference error_handler;
  3091. Обработчик ошибок, который вызывается, если возникает ошибка времени выполнения, которую может обнаружить Lua. Функция обработчика ошибок должна принимать один строковый аргумент (используйте тип std :: string, если вы хотите использовать функцию C ++, связанную с lua в качестве обработчика ошибок) и возвращать единственный строковый аргумент (опять же, возвращать std :: string или строковый аргумент из функции C ++, если вы используете его в качестве обработчика ошибок). Если исключения включены, sol попытается преобразовать .what()аргумент исключения в строку, а затем вызовет функцию обработки ошибок. Это ссылка , так как она должна ссылаться на то, что существует в реестре lua или в стеке Lua. При создании автоматически устанавливается обработчик ошибок по умолчанию protected_function.
  3092.  
  3093. Заметка
  3094.  
  3095. protected_function_resultбезопасно вызывает его значения из стека при вызове его деструктора, отслеживая индекс и количество аргументов, которые должны были быть возвращены. lua_removeНапример, если вы удалите элементы, расположенные ниже, с помощью него, он будет работать не так, как ожидалось. Пожалуйста, не выполняйте фундаментальные операции по перестановке стека, пока не будет вызван деструктор (толкание / выталкивание над ним просто отлично).
  3096.  
  3097. Чтобы узнать больше о том, как обрабатываются аргументы функции, см. Это примечание .
  3098.  
  3099. функция
  3100. вызов функций, связанных с Lua
  3101.  
  3102. Заметка
  3103.  
  3104. Эта абстракция предполагает, что функция работает безопасно. Если вы ожидаете, что в вашем коде есть ошибки (например, вы не всегда имеете явный контроль над ним или пытаетесь отлаживать ошибки), пожалуйста, явно используйте sol :: protected_function . Вы также можете сделать по sol::functionумолчанию sol::protected_function, включив функции безопасности .
  3105.  
  3106. class unsafe_function : public reference;
  3107. typedef unsafe_function function;
  3108. Функция является верной версией защищенной функции , исключающей необходимость проверок типов и обработки ошибок (таким образом, в некоторых случаях незначительно увеличивает скорость). Это тип функции по умолчанию sol. Возьмите функцию прямо из стека, используя конструктор:
  3109.  
  3110. конструктор: unsafe_function
  3111. unsafe_function(lua_State* L, int index = -1);
  3112. Вызывает конструктор и создает этот тип прямо из стека. Например:
  3113.  
  3114. funcs.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.  
  3128. int 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. функция: оператор вызова / вызов функции
  3165. template<typename... Args>
  3166. unsafe_function_result operator()( Args&&... args );
  3167.  
  3168. template<typename... Ret, typename... Args>
  3169. decltype(auto) call( Args&&... args );
  3170.  
  3171. template<typename... Ret, typename... Args>
  3172. decltype(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.  
  3182. class protected_function : public reference;
  3183. typedef 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.  
  3215. int 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
  3278. sol::protected_function problematicwoof(lua["woof"], lua["got_problems"]);
  3279.  
  3280. // dangerous if things go wrong!
  3281. double value = problematicwoof(19);
  3282. Наконец, важно отметить, что вы можете установить обработчик по умолчанию. Функция описана ниже: пожалуйста, используйте ее, чтобы избежать необходимости постоянно устанавливать обработчики ошибок:
  3283.  
  3284. // sets got_problems as the default
  3285. // handler for all protected_function errors
  3286. sol::protected_function::set_default_handler(lua["got_problems"]);
  3287.  
  3288. sol::protected_function problematicwoof = lua["woof"];
  3289. sol::protected_function problematicwoofers = lua["woofers"];
  3290.  
  3291. double value = problematicwoof(19);
  3292. double value2 = problematicwoof(9);
  3293. члены
  3294. конструктор: protected_function
  3295. template <typename T>
  3296. protected_function( T&& func, reference handler = sol::protected_function::get_default_handler() );
  3297. protected_function( lua_State* L, int index = -1, reference handler = sol::protected_function::get_default_handler() );
  3298. Создаёт protected_function. Используйте версию с двумя аргументами, чтобы легче передавать пользовательскую функцию обработки ошибок. Вы также можете установить переменную-член error_handler после создания позже. protected_functionвсегда будет использовать последний обработчик ошибок, установленный для переменной, который является либо тем, что вы передали ей, либо значением по умолчанию во время создания .
  3299.  
  3300. функция: вызов оператора / вызов защищенной функции
  3301. template<typename... Args>
  3302. protected_function_result operator()( Args&&... args );
  3303.  
  3304. template<typename... Ret, typename... Args>
  3305. decltype(auto) call( Args&&... args );
  3306.  
  3307. template<typename... Ret, typename... Args>
  3308. decltype(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. обработчики по умолчанию
  3316. static const reference& get_default_handler ();
  3317. static void set_default_handler( reference& ref );
  3318. Получите и установите объект Lua, который используется в качестве обработчика ошибок по умолчанию. По умолчанию используется обработчик ошибок no-ref. Вы можете изменить это, позвонив или подобный: все, что производит ссылку, должно быть хорошо.protected_function::set_default_handler( lua["my_handler"] );
  3319.  
  3320. переменная: обработчик
  3321. reference error_handler;
  3322. Обработчик ошибок, который вызывается, если возникает ошибка времени выполнения, которую может обнаружить Lua. Функция обработчика ошибок должна принимать один строковый аргумент (используйте тип std :: string, если вы хотите использовать функцию C ++, связанную с lua в качестве обработчика ошибок) и возвращать единственный строковый аргумент (опять же, возвращать std :: string или строковый аргумент из функции C ++, если вы используете его в качестве обработчика ошибок). Если исключения включены, sol попытается преобразовать .what()аргумент исключения в строку, а затем вызовет функцию обработки ошибок. Это ссылка , так как она должна ссылаться на то, что существует в реестре lua или в стеке Lua. При создании автоматически устанавливается обработчик ошибок по умолчанию protected_function.
  3323.  
  3324. Заметка
  3325.  
  3326. protected_function_resultбезопасно вызывает его значения из стека при вызове его деструктора, отслеживая индекс и количество аргументов, которые должны были быть возвращены. lua_removeНапример, если вы удалите элементы, расположенные ниже, с помощью него, он будет работать не так, как ожидалось. Пожалуйста, не выполняйте фундаментальные операции по перестановке стека, пока не будет вызван деструктор (толкание / выталкивание над ним просто отлично).
  3327.  
  3328. Чтобы узнать больше о том, как обрабатываются аргументы функции, см. Это примечание .
  3329.  
  3330. proxy, (protectedunsafe) _function_result - производные proxy_base
  3331. `` table [x] `` и `` function (…) `` структура преобразования
  3332.  
  3333. template <typename Recurring>
  3334. struct proxy_base;
  3335.  
  3336. template <typename Table, typename Key>
  3337. struct proxy : proxy_base<...>;
  3338.  
  3339. struct stack_proxy: proxy_base<...>;
  3340.  
  3341. struct unsafe_function_result : proxy_base<...>;
  3342.  
  3343. struct protected_function_result: proxy_base<...>;
  3344. Эти классы предоставляют оператор неявного присваивания operator=(for set) и оператор неявного преобразования (for ) для поддержки элементов, извлеченных из базовой реализации Lua, в частности sol :: table и результатов вызовов функций для sol :: function и sol :: protected_function .operator Tget
  3345.  
  3346. прокси
  3347. proxyвозвращается поисками в 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.  
  3363. int 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
  3404. requires( sol::is_primitive_type<T>::value == true )
  3405. template <typename T>
  3406. operator T() const;
  3407.  
  3408. requires( sol::is_primitive_type<T>::value == false )
  3409. template <typename T>
  3410. operator T&() const;
  3411. Получает значение, связанное с ключами, сгенерированными прокси, и передает его типу T. Обратите внимание, что эта функция всегда будет возвращать T&неконстантную ссылку на типы, которые не основаны на sol :: reference и не являются примитивным типом lua.
  3412.  
  3413. функция: получить значение
  3414. template <typename T>
  3415. decltype(auto) get( ) const;
  3416. Получает значение, связанное с ключами, и преобразует его в тип T.
  3417.  
  3418. функция: опционально получить значение
  3419. template <typename T, typename Otherwise>
  3420. optional<T> get_or( Otherwise&& otherise ) const;
  3421. Получает значение, связанное с ключами, и преобразует его в тип T. Если это не правильный тип, он возвратит sol::nulloptвместо.
  3422.  
  3423. функция: [перегружено] опционально получить или создать значение
  3424. template <typename T>
  3425. decltype(auto) get_or_create();
  3426. template <typename T, typename Otherwise>
  3427. decltype(auto) get_or_create( Otherwise&& other );
  3428. Получает значение, связанное с ключами, если оно существует. Если это не так, он установит его со значением и вернет результат.
  3429.  
  3430. operator[]прокси-только члены
  3431. функция: действует
  3432. bool valid () const;
  3433. Возвращает, действительно ли этот прокси ссылается на действительный объект. Он использует sol :: stack :: probe_get_field, чтобы определить, действительно ли он действителен.
  3434.  
  3435. функции: [перегружено] неявное множество
  3436. requires( sol::detail::Function<Fx> == false )
  3437. template <typename T>
  3438. proxy& operator=( T&& value );
  3439.  
  3440. requires( sol::detail::Function<Fx> == true )
  3441. template <typename Fx>
  3442. proxy& operator=( Fx&& function );
  3443. Устанавливает значение, связанное с ключами, с которыми был сгенерирован прокси value. Если это функция, звонки set_function. Если это не так, просто звонки set. Не существует в unsage_function_result или protected_function_result .
  3444.  
  3445. Функция: установить вызываемый
  3446. template <typename Fx>
  3447. proxy& set_function( Fx&& fx );
  3448. Устанавливает значение, связанное с ключами, с которыми был создан прокси, для функции fx. Не существует в unsafe_function_result или protected_function_result .
  3449.  
  3450. функция: установить значение
  3451. template <typename T>
  3452. proxy& set( T&& value );
  3453. Устанавливает значение, связанное с ключами, с которыми был сгенерирован прокси value. Не существует в unsafe_function_result или protected_function_result .
  3454.  
  3455. stack_proxy
  3456. sol::stack_proxyэто то, что возвращается sol :: variadic_args и другими частями фреймворка. Он похож на прокси, но предназначен для псевдонима стекового индекса, а не именованной переменной.
  3457.  
  3458. unsafe_function_result
  3459. unsafe_function_resultявляется неявным рабочим преобразования только для промежуточного и только промежуточного времени, когда вызывается функция . Он НЕ предназначен для хранения или захвата auto. Это обеспечивает быстрый доступ к нужному базовому значению. Он не реализует set/ set_function/ templated operator=, так как присутствует на прокси .
  3460.  
  3461. Этот тип, однако, разрешает доступ к нескольким базовым значениям. Используется result.get<Type>(index_offset)для получения объекта со Typeсмещением index_offsetв результатах. Смещение 0 основано. Не указав аргумент, по умолчанию значение равно 0.
  3462.  
  3463. unsafe_function_resultтакже есть begin()и end()функции, которые возвращают (почти) случайные итераторы. Они возвращают тип прокси, который может быть неявно преобразован в stack_proxy .
  3464.  
  3465. protected_function_result
  3466. protected_function_resultэто более хорошая версия, unsafe_function_resultкоторая может быть использована для обнаружения ошибок. Это дает безопасный доступ к желаемой базовой стоимости. Он не реализует set// set_functionшаблон, operator=как присутствует на прокси .
  3467.  
  3468. Этот тип, однако, разрешает доступ к нескольким базовым значениям. Используется result.get<Type>(index_offset)для получения объекта со Typeсмещением index_offsetв результатах. Смещение 0 основано. Не указав аргумент, по умолчанию значение равно 0.
  3469.  
  3470. unsafe_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.  
  3479. variadic_args
  3480. прозрачный аргумент для работы с несколькими параметрами функции
  3481.  
  3482. struct variadic_args;
  3483. Этот класс предназначен для представления каждого отдельного аргумента в его текущем индексе и за его пределами в списке функций. Он не увеличивает количество аргументов и поэтому прозрачен. Вы можете разместить его в любом месте списка аргументов, и он будет представлять все объекты в вызове функции, которые идут после него, независимо от того, перечислены они явно или нет.
  3484.  
  3485. variadic_argsтакже есть begin()и end()функции, которые возвращают (почти) итераторы со случайным доступом. Они возвращают тип прокси, который может быть неявно преобразован в тип, который вы хотите, очень похожий на тип прокси таблицы .
  3486.  
  3487.  
  3488. #define SOL_ALL_SAFETIES_ON 1
  3489. #include <sol/sol.hpp>
  3490.  
  3491. #include <iostream>
  3492.  
  3493. int 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.  
  3541. int 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"(
  3559. function a(name)
  3560. print(name)
  3561. end
  3562. store_routine(a, "some name")
  3563. )");
  3564. function_storage();
  3565.  
  3566. lua.script(R"(
  3567. function b(number, text)
  3568. print(number, "of", text)
  3569. end
  3570. store_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.  
  3586. int 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. функция: создать перегруженный набор
  3621. 1
  3622. 2
  3623. 3
  3624. 4
  3625. 5
  3626. template <typename... Args>
  3627. struct overloaded_set : tuple<Args...> { /* ... */ };
  3628.  
  3629. template <typename... Args>
  3630. overloaded_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.  
  3643. sol::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.  
  3653. struct 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.  
  3665. void ultra_bark( pup& p, int barks) {
  3666. for (; barks --> 0;) p.bark();
  3667. }
  3668.  
  3669. void picky_bark( pup& p, string s) {
  3670. if ( s == "bark" )
  3671. p.bark();
  3672. }
  3673. Затем вы используете его так же, как и для любой другой части API:
  3674.  
  3675.  
  3676. int 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
  3704. 10
  3705. 11
  3706. 12
  3707. 13
  3708. 14
  3709. 15
  3710. 16
  3711. 17
  3712. 18
  3713. 19
  3714. 20
  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.  
  3750. namespace stack
  3751. Если вы обнаружите, что абстракции более высокого уровня не соответствуют вашим потребностям, вы, возможно, захотите углубиться в stackпространство имен, чтобы попытаться получить больше от sol. stack.hppа stackпространство имен определяет несколько утилит для работы с Lua, включая утилиты push / popping, геттеры, средства проверки типов, помощники вызовов Lua и многое другое. Это пространство имен не документировано полностью, так как большая часть его интерфейса является ртутной и может меняться между выпусками, либо сильно повышать производительность, либо улучшать sol api .
  3752.  
  3753. Работу на этом уровне стека можно улучшить, если понять, как работает стек Lua в целом, а затем дополнить его объектами и предметами.
  3754.  
  3755. Однако есть несколько точек настройки ADL, которые вы можете использовать для своих целей, и несколько потенциально полезных функций. Это может помочь, если вы пытаетесь уменьшить объем кода, который вам нужно написать, или если вы хотите, чтобы ваши типы по-разному вели себя в стеке sol. Обратите внимание, что переопределение значений по умолчанию может привести к отказу от многих гарантий безопасности, которые предоставляет sol: поэтому изменяйте точки расширения по своему усмотрению.
  3756.  
  3757. структуры
  3758. структура: запись
  3759. struct 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. структура: зонд
  3772. struct 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
  3783. template<bool check_args = stack_detail::default_check_arguments, bool clean_stack = true, typename Fx, typename... FxArgs>
  3784. inline 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. функция: получить
  3788. template <typename T>
  3789. auto get( lua_State* L, int index = -1 )
  3790. template <typename T>
  3791. auto 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. функция: проверить
  3797. template <typename T>
  3798. bool check( lua_State* L, int index = -1 )
  3799.  
  3800. template <typename T, typename Handler>
  3801. bool check( lua_State* L, int index, Handler&& handler )
  3802.  
  3803. template <typename T, typename Handler>
  3804. bool 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
  3808. template <typename T>
  3809. auto get_usertype( lua_State* L, int index = -1 )
  3810. template <typename T>
  3811. auto get_usertype( lua_State* L, int index, record& tracking )
  3812. Непосредственно пытается повторно получить тип, Tиспользуя механизмы пользовательского типа sol3. Аналогично обычному getдля определенного пользователем типа. Полезно, когда вам нужно получить доступ к механизму получения пользовательских типов в sol3 и в то же время обеспечить собственную настройку .
  3813.  
  3814. функция: check_usertype
  3815. template <typename T>
  3816. bool check_usertype( lua_State* L, int index = -1 )
  3817.  
  3818. template <typename T, typename Handler>
  3819. bool check_usertype( lua_State* L, int index, Handler&& handler )
  3820.  
  3821. template <typename T, typename Handler>
  3822. bool check_usertype( lua_State* L, int index, Handler&& handler, record& tracking )
  3823. Проверяет, имеет ли объект at indexтип Tи сохраняется ли он как пользовательский тип sol3. Полезно, когда вам нужно получить доступ к механизму проверки пользовательских типов sol3, в то же время предоставляя свои собственные настройки .
  3824.  
  3825. функция: check_get
  3826. template <typename T>
  3827. auto check_get( lua_State* L, int index = -1 )
  3828. template <typename T, typename Handler>
  3829. auto 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
  3834. template <typename T, typename... Args>
  3835. int push( lua_State* L, T&& item, Args&&... args )
  3836.  
  3837. // push T that is explicitly specified, pass args... through to extension point
  3838. template <typename T, typename Arg, typename... Args>
  3839. int push( lua_State* L, Arg&& arg, Args&&... args )
  3840.  
  3841. // recursively call the the above "push" with T inferred, one for each argument
  3842. template <typename... Args>
  3843. int 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
  3848. template <typename T, typename... Args>
  3849. int push_reference( lua_State* L, T&& item, Args&&... args )
  3850.  
  3851. // push T that is explicitly specified, pass args... through to extension point
  3852. template <typename T, typename Arg, typename... Args>
  3853. int push_reference( lua_State* L, Arg&& arg, Args&&... args )
  3854.  
  3855. // recursively call the the above "push" with T inferred, one for each argument
  3856. template <typename... Args>
  3857. int multi_push_reference( lua_State* L, Args&&... args )
  3858. Эти функции ведут себя аналогично приведенным выше, но они проверяют определенные критерии и вместо этого пытаются выдвинуть ссылку, а не принудительно копировать копию, если это необходимо. Используйте его осторожно, так как sol3 использует это главным образом как возврат из функций и переменных пользовательского типа, чтобы сохранить семантику цепочки / переменной от этого объекта класса. Его внутренние компоненты обновляются в соответствии с потребностями sol3, и, хотя он, как правило, делает «правильные вещи» и его не нужно менять какое-то время, sol3 оставляет за собой право изменять свои внутренние механизмы обнаружения в соответствии с потребностями своих пользователей в любое время, как правило, без нарушения обратной совместимости и ожиданий, но не совсем гарантировано.
  3859.  
  3860. функция: поп
  3861. template <typename... Args>
  3862. auto pop( lua_State* L );
  3863. Выталкивает объект из стека Удалит фиксированное количество объектов из стека, как правило, определяется sol::lua_size<T>чертами предоставленных аргументов. Обычно это функция простоты, используемая для удобства.
  3864.  
  3865. функция: верх
  3866. int top( lua_State* L );
  3867. Возвращает количество значений в стеке.
  3868.  
  3869. функция: set_field
  3870. template <bool global = false, typename Key, typename Value>
  3871. void set_field( lua_State* L, Key&& k, Value&& v );
  3872.  
  3873. template <bool global = false, typename Key, typename Value>
  3874. void set_field( lua_State* L, Key&& k, Value&& v, int objectindex);
  3875. Устанавливает поле, на которое ссылается ключ, kна заданное значение v, помещая ключ в стек, помещая значение в стек, а затем выполняя эквивалент lua_setfieldобъекта для данного значения objectindex. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
  3876.  
  3877. функция: get_field
  3878. template <bool global = false, typename Key>
  3879. void get_field( lua_State* L, Key&& k [, int objectindex] );
  3880. Получает поле, на которое ссылается ключ k, путем нажатия ключа на стек и затем выполнения эквивалента lua_getfield. Выполняет оптимизацию и вызывает более быстрые версии функции, если тип Keyсчитается строкой в стиле c и / или если он также помечен в шаблонном globalаргументе как глобальный.
  3881.  
  3882. Эта функция оставляет полученное значение в стеке.
  3883.  
  3884. функция: probe_get_field
  3885. template <bool global = false, typename Key>
  3886. probe 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
  3897. MyType 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
  3908. int 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
  3918. template <typename Handler>
  3919. bool 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
  3936. template <typename T, typename Handler>
  3937. bool 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
  3952. template <typename T>
  3953. pair<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.  
  3972. class thread : public reference { /* ... */ };
  3973. sol::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
  3981. main_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. конструктор: резьба
  3990. thread(stack_reference r);
  3991. thread(lua_State* L, int index = -1);
  3992. thread(lua_State* L, lua_State* actual_thread);
  3993. Извлекает поток из стека Lua по указанному индексу и позволяет человеку использовать все содержащиеся в нем абстракции. Также может потребоваться фактическое состояние потока, чтобы создать поток из этого.
  3994.  
  3995. функция: просмотр состояния thread_state ()
  3996. state_view state() const;
  3997. Это извлекает текущее состояние потока, создавая представление state_view, которым можно манипулировать, как и любым другим. Сопрограммы, извлеченные из Lua с использованием состояния потока, будут запускаться именно для этого потока.
  3998.  
  3999. функция: получить объект состояния потока
  4000. lua_State* thread_state () const;
  4001. Эта функция извлекает тот, lua_State*который представляет поток.
  4002.  
  4003. текущий статус потока
  4004. thread_status status () const;
  4005. Извлекает состояние потока, которое описывает текущее состояние потока.
  4006.  
  4007. статус основного потока
  4008. bool is_main_thread () const;
  4009. Проверяет, является ли поток основным потоком Lua.
  4010.  
  4011. функция: создание потока
  4012. thread create();
  4013. static thread create (lua_State* L);
  4014. Создает новый поток из данного а lua_State*.
  4015.  
  4016. « Object :: Contents :: необязательный <T> »
  4017.  
  4018. сопрограмма
  4019. Возобновляемые / уступающие функции от Lua
  4020.  
  4021. A coroutine- это ссылка на функцию в Lua, которую можно вызывать несколько раз, чтобы получить конкретный результат. Он запускается в lua_State, который использовался для его создания (см. Поток для примера того, как получить сопрограмму, которая работает в потоке, отдельном от вашего обычного «основного» lua_State ).
  4022.  
  4023. coroutineОбъект полностью аналогичен protected_function объекта, с дополнительными функциями - членами , чтобы проверить , если сопрограмма дал ( call_status :: выданное ) , и, таким образом , снова работоспособной, была ли она завершена ( call_status :: ОК ) и , следовательно , не может дать больше значения, или произошла ошибка (см. коды ошибок status () и call_status ).
  4024.  
  4025. Например, вы можете работать с сопрограммой следующим образом:
  4026.  
  4027. co.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.  
  4038. main.cpp
  4039. sol::state lua;
  4040. lua.open_libraries(sol::lib::base, sol::lib::coroutine);
  4041. lua.script_file("co.lua");
  4042. sol::coroutine cr = lua["loop"];
  4043.  
  4044. for (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.  
  4053. main_with_thread.cpp
  4054. sol::state lua;
  4055. lua.open_libraries(sol::lib::base, sol::lib::coroutine);
  4056. lua.script_file("co.lua");
  4057. sol::thread runner = sol::thread::create(lua.lua_state());
  4058. sol::state_view runnerstate = runner.state();
  4059. sol::coroutine cr = runnerstate["loop"];
  4060.  
  4061. for (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. функция: конструктор
  4069. coroutine(lua_State* L, int index = -1);
  4070. Хватает сопрограмму по указанному индексу с учетом lua_State*.
  4071.  
  4072. возвращение статуса сопрограммы
  4073. call_status status() const noexcept;
  4074. Возвращает статус сопрограммы.
  4075.  
  4076. проверяет на ошибку
  4077. bool error() const noexcept;
  4078. Проверяет, произошла ли ошибка при запуске сопрограммы.
  4079.  
  4080. выполняемый и явный оператор bool
  4081. bool runnable () const noexcept;
  4082. explicit operator bool() const noexcept;
  4083. Эти функции позволяют проверить, можно ли еще вызывать сопрограмму (имеет больше значений для выдачи и не имеет ошибок). Если у вас есть объект сопрограммы , вы можете проверить или сделать .coroutine my_co = /*...*/runnable()if ( my_co ) { /* use coroutine */ }
  4084.  
  4085. вызывая сопрограмму
  4086. template<typename... Args>
  4087. protected_function_result operator()( Args&&... args );
  4088.  
  4089. template<typename... Ret, typename... Args>
  4090. decltype(auto) call( Args&&... args );
  4091.  
  4092. template<typename... Ret, typename... Args>
  4093. decltype(auto) operator()( types<Ret...>, Args&&... args );
  4094. Вызывает сопрограмму. Второй operator()позволяет вам указать тип возвращаемых шаблонов с использованием синтаксиса. Затем проверьте дополнительную информацию об успешном выполнении или просто проверьте объект сопрограммы в сообщении ifs, как показано выше .my_co(sol::types<int, string>, ...)status()
  4095.  
  4096. « Protected_function :: Contents :: yielding »
  4097.  
  4098. функции и вы
  4099. Sol может регистрировать все виды функций. Многие из них показаны в быстром 'n' грязном , но здесь мы обсудим множество дополнительных способов регистрации функций в системе Lua, обернутой в sol.
  4100.  
  4101. Установка новой функции
  4102. Имея функцию C ++, вы можете поместить ее в sol несколькими эквивалентными способами, работая аналогично тому, как работает установка переменных :
  4103.  
  4104. Регистрация функций C ++
  4105.  
  4106. #include <sol/sol.hpp>
  4107.  
  4108. string 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.  
  4114. int 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.  
  4135. struct 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.  
  4148. int 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 ++
  4185. 1
  4186. 2
  4187. 3
  4188. 4
  4189. template <typename A, typename B>
  4190. auto my_add( A a, B b ) {
  4191. return a + b;
  4192. }
  4193. Вы должны указать все аргументы шаблона, чтобы связать и использовать его, вот так:
  4194.  
  4195. Регистрация инстанциации шаблона функции
  4196.  
  4197. int 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
  4227. 10
  4228. 11
  4229. 12
  4230. 13
  4231. 14
  4232. int 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
  4265. 10
  4266. 11
  4267. 12
  4268. 13
  4269. 14
  4270. 15
  4271. 16
  4272. 17
  4273. 18
  4274. 19
  4275. int 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
  4297. int 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
  4342. 10
  4343. 11
  4344. 12
  4345. 13
  4346. 14
  4347. 15
  4348. int 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
  4366. int 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
  4405. 10
  4406. 11
  4407. 12
  4408. 13
  4409. 14
  4410. 15
  4411. 16
  4412. 17
  4413. 18
  4414. 19
  4415. 20
  4416. 21
  4417. 22
  4418. 23
  4419. 24
  4420. 25
  4421. 26
  4422. 27
  4423. sol::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.  
  4435. int 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. функция: создать перегруженный набор
  4457. 1
  4458. 2
  4459. 3
  4460. 4
  4461. 5
  4462. template <typename... Args>
  4463. struct overloaded_set : tuple<Args...> { /* ... */ };
  4464.  
  4465. template <typename... Args>
  4466. overloaded_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.  
  4479. sol::overload( func1, func2, ... funcN );
  4480. Функции могут быть любым видом функции / функционального объекта (лямбда). Учитывая эти функции и структуру:
  4481.  
  4482. 1
  4483. 2
  4484. 3
  4485. 4
  4486. 5
  4487. 6
  4488. 7
  4489. 8
  4490. 9
  4491. 10
  4492. 11
  4493. 12
  4494. 13
  4495. 14
  4496. 15
  4497. 16
  4498. 17
  4499. 18
  4500. 19
  4501. 20
  4502. 21
  4503. 22
  4504. 23
  4505. 24
  4506. 25
  4507. 26
  4508. 27
  4509. #define SOL_ALL_SAFETIES_ON 1
  4510. #include <sol/sol.hpp>
  4511.  
  4512. #include "assert.hpp"
  4513.  
  4514. #include <iostream>
  4515.  
  4516. struct 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.  
  4528. void ultra_bark( pup& p, int barks) {
  4529. for (; barks --> 0;) p.bark();
  4530. }
  4531.  
  4532. void 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
  4547. 10
  4548. 11
  4549. 12
  4550. 13
  4551. 14
  4552. 15
  4553. 16
  4554. 17
  4555. int 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. Вы можете работать с прозрачными аргументами, которые предоставляют вам специальную информацию, такую как
  4621. sol :: variadic_args , для обработки переменного количества аргументов во время выполнения
  4622. sol :: this_state , для получения текущего состояния Lua
  4623. sol :: 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.  
  4642. int 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.  
  4692. string(и 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.  
  4715. class unsafe_function : public reference;
  4716. typedef unsafe_function function;
  4717. Функция является верной версией защищенной функции , исключающей необходимость проверок типов и обработки ошибок (таким образом, в некоторых случаях незначительно увеличивает скорость). Это тип функции по умолчанию sol. Возьмите функцию прямо из стека, используя конструктор:
  4718.  
  4719. конструктор: unsafe_function
  4720. unsafe_function(lua_State* L, int index = -1);
  4721. Вызывает конструктор и создает этот тип прямо из стека. Например:
  4722.  
  4723. funcs.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.  
  4737. int 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. функция: оператор вызова / вызов функции
  4774. template<typename... Args>
  4775. unsafe_function_result operator()( Args&&... args );
  4776.  
  4777. template<typename... Ret, typename... Args>
  4778. decltype(auto) call( Args&&... args );
  4779.  
  4780. template<typename... Ret, typename... Args>
  4781. decltype(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 или другими встроенными функциями
  4795. Lua 5.2+ будет вести себя нормально (не включает LuaJIT 2.0.x)
  4796. Вы должны помещать контейнеры в C ++, возвращая их напрямую и получая / устанавливая их напрямую, и они будут иметь тип sol::type::userdataи обрабатываться как пользовательский тип
  4797. Контейнером можно манипулировать как из C ++, так и из Lua, и, как и пользовательские данные, будут отражать изменения, если вы используете ссылку на данные.
  4798. Это означает, что контейнеры автоматически не сериализуются как таблицы Lua
  4799. Если вам нужны таблицы, рассмотрите возможность использования sol::as_tableиsol::nested
  4800. Смотрите этот пример сериализации таблицы для более подробной информации
  4801. Lua 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.  
  4813. not_container.hpp
  4814. struct not_container {
  4815. void begin() {
  4816.  
  4817. }
  4818.  
  4819. void end() {
  4820.  
  4821. }
  4822. };
  4823.  
  4824. namespace 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.  
  4839. specializing.hpp
  4840. struct not_my_type { ... };
  4841.  
  4842. namespace 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
  4867. index_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. реализация по умолчанию увеличивает итераторы линейно для не случайного доступа
  4877. index_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 цель
  4882. target значение для контейнеров без поиска (фиксированные контейнеры, контейнеры последовательностей, неассоциативные и неупорядоченные контейнеры)
  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
  4892. 2-й аргумент (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()
  4916. ipairs 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
  4934. find операция линейна по размеру списка (ищет все элементы)
  4935. std :: forward_list имеет итераторы только для пересылки: set / find является линейной операцией
  4936. std :: forward_list использует идиому «insert_after», требует специальной внутренней обработки
  4937. фиксированный не хватает push_back/ insert не хватаетerase std :: array <T, n> T [n] (фиксированные массивы)
  4938. обычные массивы в стиле c должны быть установлены или использоватьсяref( arr )&arr
  4939. C ++ реализация вставляет с помощью оператора []
  4940. приказал key_type ЬурейеЕ erase(key) find(key) insert(key) std :: set std :: multi_set
  4941. container[key] = stuffоперация стирает, когда stuffноль, вставляет / устанавливает, когда нет
  4942. container.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
  4945. container[key] = stuffоперация стирает, когда stuffноль, вставляет / устанавливает, когда нет
  4946. container.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.  
  4959. int main(int, char**) {
  4960. cout << "=== containers ===" << endl;
  4961.  
  4962. sol::state lua;
  4963. lua.open_libraries();
  4964.  
  4965. lua.script(R"(
  4966. function 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()
  4973. end
  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"(
  4999. arr:add(28)
  5000. )");
  5001.  
  5002. // Call it, see *7* elements
  5003. // printed out
  5004. f(lua["arr"]);
  5005.  
  5006. lua.script(R"(
  5007. arr: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.  
  5019. iteration.lua
  5020. 1
  5021. 2
  5022. 3
  5023. for i = 1, #vec do
  5024. print(i, vec[i])
  5025. end
  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.  
  5039. int 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. учебник по настройке
  5087. API документация
  5088. документация памяти
  5089. В папке примеров также есть несколько действительно хороших примеров для просмотра. Ниже также приведены некоторые примечания о гарантиях, которые вы можете найти о пользовательских типах и связанных с ними пользовательских данных:
  5090. Контейнеры выдвигаются как специальные пользовательские типы, но могут быть отключены, если возникают проблемы, как подробно описано здесь .
  5091. Определенные операторы обнаруживаются и автоматически связываются для пользовательских типов
  5092. Вы можете использовать битовые поля, но это требует некоторой утонченности с вашей стороны. У нас есть пример, чтобы помочь вам начать здесь, который использует несколько хитростей .
  5093. Все типы пользователей расширяются во время выполнения как в Lua, так и в C ++
  5094. Если вам нужны динамические обратные вызовы или переопределяемые во время выполнения функции, используйте functionпеременную-член и получите / установите ее для объекта usertype
  5095. functionработает как переменная-член или при передаче в качестве аргумента / возвращает значение (вы даже можете использовать его с 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
  5106. obj:method_name() как вы называете «член» методы в Lua
  5107. Это чисто синтаксический сахар, который передает имя объекта в качестве первого аргумента method_nameфункции
  5108. my_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свободно использовать любой пользовательский тип, который хотите переопределить, по умолчанию «если ключ отсутствует, найти его / установить его здесь» функциональность определенного объекта пользовательского типа.
  5121. new_indexи indexне будет вызван, если вы попытаетесь манипулировать именованной таблицей пользовательских типов напрямую. Sol3 будут вызваны для добавления этой функции в таблицу поиска функций / переменных пользовательского типа.
  5122. new_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.  
  5137. T относится к типу, превращаемому в тип пользователя.
  5138.  
  5139. class metatable : public table;
  5140.  
  5141. template <typename T>
  5142. class usertype : public metatable;
  5143. В то время как другие платформы расширяют синтаксис lua или создают языки структуры данных (DSL) для создания классов в Lua, sol вместо этого предлагает возможность генерировать легкие привязки, которые снижают производительность. Вы можете увидеть небольшой стартовый пример здесь . Они используют метатаблицы и пользовательские данные в Lua для их реализации. Типы пользователей также могут быть расширены во время выполнения .
  5144.  
  5145. Существуют более сложные варианты использования для создания и использования пользовательского типа, которые основаны на том, как использовать функцию .set () и ее первоначальную конструкцию (см. Ниже).
  5146.  
  5147. перечисления
  5148. перечисление meta_function для имен
  5149.  
  5150. enum 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.  
  5192. typedef 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.  
  5197. meta_function::indexи meta_function::new_indexприменяется строго к тому, когда объект в Lua вызывается с ключом, которого он еще не знает (например, он не был связан программистом C ++ с помощью .set(...)или .new_usertype<...>(...);. meta_function::static_indexи функции meta_function :: static_new_index` вызываются, когда ключ не найден и Пользователь вызывает новую функцию из названной метатаблицы.
  5198.  
  5199. структуры
  5200. automagic_enrollments для специальных членов, определенных в классе
  5201. 1
  5202. 2
  5203. 3
  5204. 4
  5205. 5
  5206. 6
  5207. 7
  5208. 8
  5209. 9
  5210. 10
  5211. 11
  5212. struct 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.  
  5225. new_usertype / set
  5226. sol::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.  
  5228. new_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. Этот синтаксис длиннее и предоставляется для обратной совместимости: приведенный выше синтаксис аргумента короче и чище
  5236. Type-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
  5251. sol::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& )
  5278. sol::meta_function::to_stringоператор будет создан
  5279. запись делается либо
  5280. ostringstreamдо базовой строки сериализации в 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, например:
  5284. namespace sol {
  5285. template <>
  5286. struct is_to_stringable<my_type> : false_type {};
  5287. }
  5288. для операций вызова, где существует тип C ++operator()( parameters ... )
  5289. sol::meta_function::callоператор будет создан
  5290. оператор вызова функции в C ++ не должен быть перегружен, иначе sol не сможет связать его автоматически
  5291. оператор вызова функции в C ++ не должен быть шаблонным, иначе sol не сможет связать его автоматически
  5292. если он перегружен или настроен, это ваша ответственность, чтобы связать его правильно
  5293. для автоматической итерации, где begin()и end()существуют на типе C ++
  5294. sol::meta_function::pairsоператор генерируется для вас
  5295. Позволяет вам повторять использование в Luafor k, v in pairs( obj ) do ... end
  5296. Lua 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. Выгрузка нескольких функций с одним и тем же именем не создает перегрузки : вы должны использовать этот синтаксис, чтобы он работал
  5323. sol::base_classes, sol::bases<Bases...>
  5324. Сообщает типу пользователя, каковы его базовые классы. Это необходимо для правильной работы преобразований из базы в базу. См наследство
  5325. регистрацию
  5326. Вы можете разъединить и убить UserType и связанную с ним функциональность, позвонив .unregister()на sol::usertype<T>или sol::metatableуказал на соответствующую sol3 метатаблицы. Это полностью разъединит и очистит внутренние структуры поиска sol3 и ключевую информацию.
  5327.  
  5328. функции времени выполнения
  5329. Вы можете добавлять функции во время выполнения ко всему классу (не к отдельным объектам). Установите имя под метатабельным именем, которое вы привязали new_usertypeк объекту. Например:
  5330.  
  5331. runtime_extension.cpp
  5332.  
  5333. #define SOL_ALL_SAFETIES_ON 1
  5334. #include <sol/sol.hpp>
  5335.  
  5336. #include <iostream>
  5337.  
  5338. struct object {
  5339. int value = 0;
  5340. };
  5341.  
  5342. int 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. наследство
  5369. Sol может корректировать указатели от производных классов до базовых классов во время выполнения, но у него есть некоторые предостережения, основанные на том, что вы компилируете:
  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.  
  5386. struct A {
  5387. int a = 10;
  5388. virtual int call() { return 0; }
  5389. virtual ~A(){}
  5390. };
  5391. struct B : A {
  5392. int b = 11;
  5393. virtual int call() override { return 20; }
  5394. };
  5395.  
  5396. int 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.  
  5417. Sol не поддерживает преобразование из базового класса в производный класс во время выполнения.
  5418.  
  5419. Предупреждение
  5420.  
  5421. Укажите все переменные-члены базового класса и функции-члены, чтобы избежать предостережений текущей реализации относительно автоматического поиска базового члена. В настоящее время sol пытается связать методы и переменные базового класса с их производными классами с помощью недокументированной неподдерживаемой функции, если вы укажете это sol::bases<...>. К сожалению, это может происходить за счет производительности, в зависимости от того, «далеко» ли база от производного класса в списке поиска баз. Если вы не хотите страдать от снижения производительности, пока мы сглаживаем изломы в реализации (и хотим, чтобы он оставался постоянным всегда), укажите все базовые методы для производного класса в списке методов, который вы пишете. В будущем мы надеемся, что с размышлениями нам не придется беспокоиться об этом.
  5422.  
  5423. автоматические типы пользователей
  5424. Типы пользователей автоматически регистрируют специальные функции, независимо от того, связаны они или нет с помощью new_usertype . Вы можете отключить это, специализируя sol::is_automagical<T>черту шаблона:
  5425.  
  5426. struct my_strange_nonconfirming_type { /* ... */ };
  5427.  
  5428. namespace sol {
  5429. template <>
  5430. struct is_automagical<my_strange_nonconforming_type> : false_type {};
  5431. }
  5432. наследование + перегрузка
  5433. Несмотря на то, что перегрузка поддерживается независимо от предостережений наследования или нет, текущая версия sol имеет стиль перегрузки по первому совпадению при первом вызове, когда дело доходит до наследования. Сначала поместите функции с наиболее производными аргументами, чтобы получить ожидаемое совпадение или приведение внутри промежуточной функции C ++, и вызовите нужную функцию.
  5434.  
  5435. скорость компиляции
  5436. Заметка
  5437.  
  5438. MSVC и clang / gcc могут понадобиться дополнительные флаги компилятора для обработки компиляции с широким использованием пользовательских типов. Смотрите: документацию по ошибкам для более подробной информации.
  5439.  
  5440. Примечание о производительности
  5441. Заметка
  5442.  
  5443. Обратите внимание, что производительность для вызовов функций-членов снижается из-за фиксированных накладных расходов, если вы также связываете переменные и функции-члены. Это чисто ограничение реализации Lua, и, к сожалению, с этим ничего нельзя поделать. Однако если вы связываете только функции, а не переменные, sol автоматически оптимизирует время выполнения Lua и даст вам максимально возможную производительность. Пожалуйста, учтите простоту использования и обслуживания кода, прежде чем превращать все в функции.
  5444.  
  5445. память типа пользователя
  5446. расположение в памяти пользовательских типов
  5447.  
  5448. Заметка
  5449.  
  5450. Sol не берет на себя владение необработанными указателями, возвращенными из функций или установленными через 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-^
  5474. Lua очистит саму память, но не знает ни о какой семантике уничтожения, которую может навязать 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. Что это значит?
  5505. sol3 в основном совместим с предыдущим 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::стилю включения, чтобы помочь предотвратить столкновения.
  5511. C ++ 17 включен. Определения, включающие возможности C ++ 17, все еще существуют из-за чистой лени: теперь это библиотека C ++ 17.
  5512. Производительность хороша ™.
  5513. Поскольку это значительное увеличение версии, часть кода, написанного людьми ранее, сломается. Вот хорошая новость: большая часть вашего кода не сломается, и ничего более фундаментального или ядра в sol2 на самом деле не сломалось. Просто вещи, которые были уже ужасны.
  5514.  
  5515. Пользовательские удаления и очистка
  5516. Это были первоочередные цели, которые нужно было исправить, но в конечном итоге это было легко, так как в основном это было связано с моим [delete]ключом и увлечением тем, как вещи исчезают.
  5517.  
  5518. new_simple_usertypeи simple_usertypeобъекты больше не существуют. Они были хакерами для увеличения пропускной способности времени компиляции, в то же время заставляя пользователя оплачивать затраты времени выполнения в некоторых случаях Больше не нужно, и код работает так быстро, как может быть всегда: это было удалено .
  5519. sol::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.  
  5524. struct blah {
  5525. int a;
  5526. bool b;
  5527. char c;
  5528. double d;
  5529. /* ... */
  5530. };
  5531.  
  5532. constexr int some_static_class_value = 58;
  5533.  
  5534. int 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.  
  5555. sol::stack::pusher, sol::stack::checkerИ т.д. - борьба со мной , чтобы убедиться , что я не наступайте на ваши настройки точек специализации действительно отстой.
  5556. Специализация этих старых имен сейчас не компилируется. Старые имена больше не существуют, чтобы убедиться, что это была серьезная ошибка компилятора, и что внесенные мной изменения не изменили время выполнения вашей программы и не дадут вам день отладочного приключения.
  5557. Производительность не изменилась, но небрежный код наверняка изменился. Этот кусок кода, заполненного шаблонами, теперь можно заменить:
  5558.  
  5559. struct two_things {
  5560. int a;
  5561. bool b;
  5562. };
  5563.  
  5564. namespace 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.  
  5615. struct two_things {
  5616. int a;
  5617. bool b;
  5618. };
  5619.  
  5620. template <typename Handler>
  5621. bool sol_lua_check(sol::types<two_things>, lua_State* L, int index,
  5622. Handler&& 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.  
  5630. two_things sol_lua_get(sol::types<two_things>, lua_State* L, int index,
  5631. sol::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.  
  5639. int 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.  
  5660. if constexpr? Но Derpstorm, как насчет моего {старого компилятора здесь} ?!
  5661. Я давным-давно высказал предположение, что sol3 будет использовать технологию C ++ 17 (например, почти 2 года назад?), В основном, чтобы сэкономить мне скорость компиляции и здравый смысл. Поскольку sol3 - это библиотека с открытым исходным кодом, я делаю это для удовольствия, а не для выгоды. Что переводится как:
  5662.  
  5663. Requests Потяните запросы добро пожаловать! 🎉
  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.  
  5676. int 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.  
  5716. const 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.  
  5729. int 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.  
  5747. const char* LUA = R"(
  5748.  
  5749. function loop()
  5750. for i = 1, 10 do
  5751. print(i)
  5752. coroutine.yield()
  5753. end
  5754. end
  5755. )";
  5756.  
  5757. int 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.  
  5775. const 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)
  5782. end
  5783. function main2(x, y)
  5784. coroutine.yield(10)
  5785. print(x, y)
  5786. end
  5787. start_thread(main, 10, 12, 8)
  5788. start_thread(main2, 1, 2)
  5789. )";
  5790.  
  5791. int 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.  
  5820. lua.script(LUA);
  5821.  
  5822. cout << endl;
  5823.  
  5824. return 0;
  5825. };
  5826. using 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)
  5833. end
  5834. function main2(x)
  5835. coroutine.yield(10)
  5836. print(x)
  5837. end
  5838. start_thread(main, 10)
  5839. start_thread(main2, 1)
  5840. )";
  5841.  
  5842. int 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. };
  5871. const char* LUA = R"(
  5872. function main(x)
  5873. coroutine.yield(20)
  5874. print(x)
  5875. end
  5876. function main2(x)
  5877. coroutine.yield(10)
  5878. print(x)
  5879. end
  5880. start_thread(main, 10)
  5881. start_thread(main2, 1)
  5882. )";
  5883.  
  5884. int 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. };
  5914. const char* LUA1 = R"(
  5915. while true do
  5916. print()
  5917. end
  5918. )";
  5919. const char* LUA = R"(
  5920. while true do
  5921. print('Hello world!')
  5922. end
  5923. )";
  5924. int 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.  
  5934. struct 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.  
  5959. struct 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.  
  5988. const auto& script = R"(counter = 20
  5989. function loop()
  5990. while counter ~= 30
  5991. do
  5992. coroutine.yield(counter);
  5993. counter = counter + 1;
  5994. end
  5995. return counter
  5996. end
  5997. )";
  5998.  
  5999. int main(int argc, char* argv[]) {
  6000. state lua;
  6001. lua.open_libraries(lib::base, lib::table, lib::coroutine);
  6002. {
  6003. auto code = R"(
  6004. unpack = unpack or table.unpack
  6005. function 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
  6013. end
  6014. loop_th = coroutine.create(loop)
  6015. loop_res = function(...)
  6016. returns = { coroutine.resume(loop_th, ...) }
  6017. return unpack(returns, 2)
  6018. end
  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.  
  6074. cout << endl;
  6075.  
  6076. return 0;
  6077. };
  6078.  
  6079.  
  6080. struct coro_h {
  6081. int x = 500;
  6082. int func() {
  6083. x += 1;
  6084. return x;
  6085. }
  6086. };
  6087.  
  6088. struct 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.  
  6113. struct 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
  6143. function loop()
  6144. while counter ~= 30
  6145. do
  6146. coroutine.yield(counter);
  6147. counter = counter + 1;
  6148. end
  6149. return counter
  6150. end
  6151. )";
  6152.  
  6153. int 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.  
  6187. a separate state that can contain and run functions
  6188. class thread : public reference { /* ... */ };
  6189. sol::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>`
  6190. Note
  6191. A 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.
  6192. free function
  6193. The 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>`).
  6194. Warning
  6195. This 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.
  6196. members
  6197. Takes 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.
  6198. This 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.
  6199. This function retrieves the lua_State* that represents the thread.
  6200. Retrieves the :doc:`thread status<types>` that describes the current state of the thread.
  6201. Checks to see if the thread is the main Lua thread.
  6202. Creates a new thread from the given a lua_State*.
  6203.  
  6204.  
  6205.  
  6206. int 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"(
  6212. local a,b,c = ...
  6213. print(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. };
  6226. void some_function() {
  6227. cout << "some function!" << endl;
  6228. }
  6229.  
  6230. void some_other_function() {
  6231. cout << "some other function!" << endl;
  6232. }
  6233.  
  6234. struct some_class {
  6235. int variable = 30;
  6236. double member_function() {
  6237. return 24.5;
  6238. }
  6239. };
  6240.  
  6241. int 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.  
  6296. int 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.  
  6325. int 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.  
  6378. int 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.  
  6425. int 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. };
  6445. int 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. };
  6510. int 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.  
  6546. int 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.  
  6578. int 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.  
  6596. struct 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.  
  6608. void ultra_bark(pup& p, int barks) {
  6609. for (; barks-- > 0;) p.bark();
  6610. }
  6611.  
  6612. void picky_bark(pup& p, string s) {
  6613. if (s == "bark")
  6614. p.bark();
  6615. }
  6616.  
  6617. int 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. };
  6650. struct 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.  
  6662. void ultra_bark(pup& p, int barks) {
  6663. for (; barks-- > 0;) p.bark();
  6664. }
  6665.  
  6666. void picky_bark(pup& p, string s) {
  6667. if (s == "bark")
  6668. p.bark();
  6669. }
  6670. struct some_class {
  6671. int bark = 2012;
  6672. };
  6673.  
  6674. sol::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.  
  6690. int 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"(
  6701. s = my_lib.some_class.new()
  6702. assert(my_lib.func() == 2)
  6703. s.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
  6717. int 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.  
  6740. int 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
  6793. class scheduler_task
  6794. {
  6795. public:
  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
  6804. class callback_task : public scheduler_task
  6805. {
  6806. public:
  6807. callback_task(function<bool()> callback)
  6808. : m_callback(callback)
  6809. {
  6810. }
  6811.  
  6812. bool is_complete()
  6813. {
  6814. return m_callback();
  6815. }
  6816.  
  6817. private:
  6818. function<bool()> m_callback;
  6819. };
  6820.  
  6821.  
  6822. namespace detail {
  6823. struct scheduler_cothread;
  6824. struct scheduler_thread_task;
  6825. struct scheduler_task_list;
  6826. struct thread_stack;
  6827. }
  6828.  
  6829. class scheduler
  6830. {
  6831. public:
  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.  
  6860. private:
  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.  
  6868. namespace 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.  
  6896. scheduler::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.  
  6904. scheduler::~scheduler()
  6905. {
  6906. }
  6907.  
  6908.  
  6909. void 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.  
  6924. void 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.  
  6958. void 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.  
  6966. int scheduler::pending_tasks()
  6967. {
  6968. return m_tasks->tasks.size();
  6969. }
  6970.  
  6971.  
  6972.  
  6973. class wait_task : public scheduler_task
  6974. {
  6975. public:
  6976. wait_task(int secs) : m_secs(secs), m_start(time(0)) {}
  6977. bool is_complete() { return ((time(0) - m_start) >= m_secs); }
  6978. private:
  6979. int m_secs;
  6980. time_t m_start;
  6981. };
  6982.  
  6983. struct 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.  
  6995. int func() {
  6996. cout << "C++ - Inside f" << endl;
  6997. return 24;
  6998. }
  6999.  
  7000. void 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.  
  7017. int 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.  
  7067. int 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.  
  7073. std::thread t([=]() {
  7074. lua["f"](0);
  7075. });
  7076. t.detach();
  7077. return 0; // все, что требуется для работы с необработанной функцией.
  7078. };
  7079.  
  7080. int 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.  
  7096. lua_pushlightuserdata(L, L); /* отправить адрес памяти переменной в стек */
  7097. lua_pushstring(L, luafile); /* отправить значение в стек */
  7098. lua_settable(L, LUA_REGISTRYINDEX); /* уст ключа и значение таблице реестре. */
  7099. //lua_pushlightuserdata(L, L); /*отправить адрес, который является ключом в стек. */
  7100. //lua_gettable(L, LUA_REGISTRYINDEX); /* получить таблицу и значение ключа будет в -1 */
  7101. //char const* str1 = lua_tostring(L, -1);
RAW Paste Data Copied