关键词:C/C++、模板、template、反射、Lua、API、绑定、自动化、开发、效率、成本
痛点:
C/C++没有完美的反射功能(如golang/delphi),对开发 Lua ⟷ C API 来说是比较繁琐和耗工时的,并且人工编码的出错率也非常高。
方案
C++模板编译期自动化推导。
优点
•性能高(相比于反射)
•提高开发效率(相比与人工)
•出错率极低(相比与人工)
示例
示例1:注册 C++ 函数到 Lua
示例2:从 C++ 调用 Lua 函数(无函数指针方式)
示例3:从 C++ 调用 Lua 函数(函数指针方式)
代码
[code]/********************************************************************************** * * 自动化 Lua ⟷ C API功能模块 * * author: ygluu * * 1、Lua->C: 自动推导和注册C-Func参数和返回值给Lua调用 * 函数 alua::reg_lua(L, mod_name, func_name) * * 2、C->Lua: 自动推导C-Call语句的参数和返回值并调用Lua函数 * * 无返回值调用(常用) * alua::call_lua(L, mod_name, func_name, lua-args...); * * 显式返回类型调用(常用) * * int ret = alua::call_lua(L, mod_name, func_name, lua-args...); * * std::tuple ret = alua::call_lua(L, mod_name, func_name, lua-args...); * * std::map ret = alua::call_lua(L, mod_name, func_name, lua-args...); * * 隐式返回类型调用(需声明与LUA函数一致的c-func声明) * auto ret = alua::call_lua(...); * * 参数和返回值类型支持: * 1、基础类型:int/uint32/int64/uint64/string(const char*)/bool * 2、数组:std::vector * 3、元组:std::tuple * 4、字典:std::map/std::unordered_map * * **********************************************************************************/#pragma once#include "lua.hpp"#include #include #include #include #include #include #include namespace alua{ // 工具:把 __PRETTY_FUNCTION__ 里的裸函数名取出来 namespace { // 判断是否是 tuple template inline constexpr bool is_tuple_v = false; template inline constexpr bool is_tuple_v = true; // 计算期望返回数量 template constexpr int expected_returns() noexcept { if constexpr (std::is_same_v) return 0; else if constexpr (is_tuple_v) return std::tuple_size_v; else return 1; } constexpr std::string_view raw_name(std::string_view pretty) noexcept { std::size_t tail = pretty.rfind('('); if (tail == std::string_view::npos) { return pretty; } std::size_t head = pretty.rfind(' ', tail); return (head == std::string_view::npos) ? pretty.substr(0, tail) : pretty.substr(head + 1, tail - head - 1); } // 单值读取 / 压栈 template struct popper; template struct pusher; // 数值 template struct popper { static int get(lua_State* l,int i){return static_cast(luaL_checkinteger(l,i));}}; template struct popper { static float get(lua_State* l,int i){return static_cast(luaL_checknumber(l,i));}}; template struct popper { static double get(lua_State* l,int i){return luaL_checknumber(l,i);}}; template struct popper { static bool get(lua_State* l,int i){return lua_toboolean(l,i)!=0;}}; template struct popper { static std::uint32_t get(lua_State* l,int i){return static_cast(luaL_checkinteger(l,i));}}; template struct popper { static std::uint64_t get(lua_State* l,int i){return static_cast(luaL_checkinteger(l,i));}}; template struct popper { static std::int64_t get(lua_State* l,int i){return static_cast(luaL_checkinteger(l,i));}}; // 字符串 template struct popper { static std::string get(lua_State* l,int i) { std::size_t len = 0; const char* s = luaL_checklstring(l,i,&len); return std::string{s,len}; } }; template struct popper { static const char* get(lua_State* l,int i){return luaL_checkstring(l,i);}}; // 轻量 userdata template struct popper { static void* get(lua_State* l,int i){return lua_touserdata(l,i);}}; // 压栈 template struct pusher { static void put(lua_State* l,int v){lua_pushinteger(l,v);}}; template struct pusher { static void put(lua_State* l,float v){lua_pushnumber(l,v);}}; template struct pusher { static void put(lua_State* l,double v){lua_pushnumber(l,v);}}; template struct pusher { static void put(lua_State* l,bool v){lua_pushboolean(l,v);}}; template struct pusher { static void put(lua_State* l,std::uint32_t v){lua_pushnumber(l,v);}}; template struct pusher { static void put(lua_State* l,std::uint64_t v){lua_pushnumber(l,v);}}; template struct pusher { static void put(lua_State* l,std::int64_t v){lua_pushnumber(l,v);}}; template struct pusher { static void put(lua_State* l,const std::string& v){lua_pushlstring(l,v.data(),v.size());}}; template struct pusher { static void put(lua_State* l,const char* v){lua_pushstring(l,v);}}; template struct pusher { static void put(lua_State* l,void* v){lua_pushlightuserdata(l,v);}}; // vector template struct popper { static std::vector get(lua_State* l,int idx) { luaL_checktype(l,idx,LUA_TTABLE); std::vector v; lua_pushnil(l); while(lua_next(l,idx)!=0) { v.emplace_back(popper::get(l,-1)); lua_pop(l,1); } return v; } }; template struct pusher { static void put(lua_State* l,const std::vector& v) { lua_createtable(l,static_cast(v.size()),0); for(std::size_t i=0;i |