c++调用lua函数——C++熟悉方式调用

目录

lua_proxy模板类实现

调用lua函数实例

注意事项


lua_proxy模板类实现

c++调用lua要用到模拟栈,调用函数比较复杂。如下写了一个模板,用来以C++熟悉的方式进行lua函数调用,就很方便。目前只写了C++11版本的,如果要适配C++11之前的版本,需要进行一些改动。

#ifndef _LUA_PROXY_H_
#define _LUA_PROXY_H_
#include <tuple>
#include <string>
#include "lua.hpp"

class nil_t
{
};
nil_t nil;

class lua_proxy
{
private:
	lua_State*      m_status;
private:
	template <typename val_t>
	void push_type(val_t i_data) const {}

	template <>
	void push_type<int>(int i_data) const
	{
		lua_pushinteger(m_status, i_data);
	}

	template<>
	void push_type<double>(double d_data) const
	{
		lua_pushnumber(m_status, d_data);
	}

	template <>
	void push_type<bool>(bool b_data) const
	{
		lua_pushboolean(m_status, b_data ? 1 : 0);
	}

	template <>
	void push_type<nil_t>(nil_t nil_data) const
	{
		lua_pushnil(m_status);
	}

	template <>
	void push_type<const char *>(const char *cstr_data) const
	{
		lua_pushstring(m_status, cstr_data);
	}

private:
	class ret_type
	{
	public:
		int				m_top_idx;			// 调用前栈位置
		lua_State*		m_status;
	public:
		ret_type() {}
		ret_type(lua_State* ptr_status, const int& i_top_idx) : m_status(ptr_status), m_top_idx(i_top_idx)
		{}
		ret_type(const ret_type& other) = delete;
		ret_type(ret_type&& other)
		{
			m_status = other.m_status;
			m_top_idx = other.m_top_idx;
			other.m_status = nullptr;
			other.m_top_idx = 0;
		}
		virtual ~ret_type()
		{
			if (m_status)
			{
				lua_settop(m_status, m_top_idx);
			}
		}
		template<typename...vals_t>
		operator std::tuple<vals_t...>()
		{
			/* 对m_status操作,获取返回值 */
			return gets<-(int)sizeof...(vals_t), vals_t...>();
		}

		template<typename...vals_t>
		void get_tie(std::tuple<vals_t&...> tp)
		{
			tp = std::tuple<vals_t...>() = *this;
		}

		template<int idx, typename val_t, typename...vals_t>
		std::tuple<val_t, vals_t...> gets() const
		{
			std::tuple<val_t> t1{ get<val_t>(m_status, idx) };
			if constexpr (sizeof...(vals_t) == 0)
			{
				return t1;
			}
			else
			{
				return std::tuple_cat(t1, gets<idx + 1, vals_t...>());
			}
		}

		template<typename val_t>
		val_t get(lua_State* L, int idx) const {}

		template<>
		int get<int>(lua_State* L, int idx)const
		{
			int itype = lua_type(L, idx);
			auto ret = lua_tonumber(L, idx);
			return ret;
		}

		template<>
		std::string get<std::string>(lua_State* L, int idx)const
		{
			return lua_tostring(L, idx);
		}

		template<>
		double get<double>(lua_State* L, int idx)const
		{
			int itype = lua_type(L, idx);
			auto ret = lua_tonumber(L, idx);
			return ret;
		}
	};

public:
	lua_proxy() :m_status()
	{
		m_status = luaL_newstate();
		luaL_openlibs(m_status);
	}

	virtual ~lua_proxy()
	{
		lua_close(m_status);
	}

	lua_State* get_status() const
	{
		return m_status;
	}

	void push_stack_value(const int& i_stack_idx) const
	{
		lua_pushvalue(m_status, i_stack_idx);
	}

	void set_top_to_stack_idx(const int& i_stack_idx) const
	{
		lua_replace(m_status, i_stack_idx);
	}

	void set_stack_idx_to_top(const int& i_stack_idx) const
	{
		lua_settop(m_status, i_stack_idx);
	}

	void remove_stack_idx(const int& i_stack_idx) const
	{
		lua_remove(m_status, i_stack_idx);
	}

	int stack_size() const
	{
		return lua_gettop(m_status);
	}

	template <typename val_t, typename... vals_t>
	void push(val_t val, vals_t... vals) const
	{
		push_type(val);
		if constexpr (sizeof...(vals) != 0)
		{
			push(vals...);
		}
	}

	template<typename...vals_t>
	ret_type pcall(const char* cstr_func_name, vals_t...vals)
	{
		int i_ret_pos = lua_gettop(m_status);
		int i_ret = lua_getglobal(m_status, cstr_func_name);
		if (i_ret != 0)
		{
			/* 函数查找失败 */
		}
		push(vals...);
		/*压入数据并调用函数*/
		i_ret = lua_pcall(m_status, sizeof...(vals), LUA_MULTRET, 0);
		if (i_ret != 0)
		{
			/* 调用失败 */
		}
		return ret_type{ m_status, i_ret_pos };
	}

	int load(const char* cstr_file_path)
	{
		int i_ret = luaL_dofile(m_status, cstr_file_path);
		return i_ret;
	}
};

#endif

调用lua函数实例

lua脚本,用于被调用,文件名“main.lua”。

function test(x,y)
    print(x ,y)
    return x,y
end

调用示例

#include <conio.h>
#include <lua.hpp>
#include "lua_proxy.h"

/* 函数生成器 */
template<typename ret_t, typename...paras_t>
std::function<ret_t(paras_t...)> get_func(lua_proxy* plu, const char* cstr_func_name)
{
	std::string str_func_name = cstr_func_name;
	return [plu, str_func_name](paras_t...paras)->auto
	{
		return plu->pcall(str_func_name.c_str(), paras...);
	};
}

int main()
{
	std::tuple<int> t1{1};
	lua_proxy lu;
	int iret = lu.load("main.lua");
	int x = 0; double y = .0;
	std::tuple<int, double> tp;
    lu.pcall("test", 1, 1.1).get_tie(std::tie(x, y));    // lua函数调用并转tie
    tp = lu.pcall("test", 1, 1.1);                       // lua函数调用并转tuple
    // auto k = lu.pcall("test", 1, 1.1);                // 这种调用会导致无法回滚到栈顶,直到k析构
    /* 推荐调用方法 */
    auto lua_test = get_func<std::tuple<int,double>,int,double>(&lu, "test");// 定义lua_test函数
	std::tie(x,y) = lua_test(1, 1.2);        // 调用lua_test函数
	_getch();
}

上面的代码展示了三种调用的方法。第一种调用方法通过get_tie直接将返回的多个返回值赋值给x,y;第二种调用方式返回一个tuple;第三种使用了一个小技巧,通过get_func函数返回了一个闭包,其中保存有需要调用的函数名和lua_proxy;获得闭包后再调用lua_test就是调用了lua脚本中的test函数,并且能够正确的获得返回值。

注意事项

回值会在返回的ret_type析构时自动回退,由于ret_type为内部类,所以在外部不能直接构建,但是由于auto的存在,依然能在外部构建出该对象,因此要注意pcall的返回值不要直接使用auto接,这样会导致栈无法回滚。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

腾昵猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值