20140102-lua binder另一只轮子的雏形

书接上一回,说到要继续丰富对类型的处理。那么如何才能做到呢,应该是要支持自定义的,所以这一回要讲的就是在前面的基础上,增加支持自定义部分,其中包含以下几个部分

  • 函数的默认参数设置,包括有几个默认参数和如何设置这些默认参数;
  • 可以做为返回值的参数下标(Lua支持多值返回);
  • 如何将函数的结果和当做返回值的函数的参数压入到Lua;
  • 如何将函数的结果压入到Lua中(看起来和上一点重复,默认情况下是调用上一条进行压入Lua);
  • 将当做返回值的函数的参数(所有需要返回的)压入Lua;
  • 如何确定中间存放函数参数的值的类型;
  • 从Lua中提取函数的参数;
  • 将中间存放的函数的参数的值打扮成函数需要的实参;

发现没有,关键的一条,函数的调用居然没有支持自定义。

说了这么多,我们先来瞄一眼改装后的打包过程大概是个什么样子:

	lua_register(L, "h", (
			xLB_CFunc::b<decltype(&h), // type of function
			&h, // pointer of function
			0, // count of default parameters for function
			xLB_dfer, // setter for default parameters for function
			xLB_idxer<>, // index of parameters for return
			xLB_pper, // how each value pushed into Lua
			xLB_rner, // how the result of function pushed into Lua
			xLB_pter, // how those parameters after function calling pushed into Lua
			My_vter, // decide what type of value for saving the function parameters
			My_lver, // how the value load from Lua
			xLB_vper // make values as function's parameters
			>()));


感觉象不象一怪物,只是绑定一个小小的函数,居然要写这么多代码。实际上支持了默认参数,如果不做自定义,只要前面两个模板参数就可以了。当然,提供更多更简便的包装办法是必须的,得等下一篇了。

主要的C++11技术前两篇都说得差不多了,这里要提一下的是,怎么设置函数的默认参数,实际上默认参数设置的自定义支持是一个星期天才写的(新鲜)。为什么要说它呢,它和别的自定义支持有啥不同呢,是因为默认参数是值,不是类型,也不是函数,没办法做为模板参数来提供给打包模板(其实你早就知道了对不)。所以C++11提供的选择不过,听说以后的版本会支持将值和对象一类的东东做为模板参数(谁说值不能做为模板参数,象int类型的值不是可以么)。说得太不准确了,一般编译器的提示是none type一类。因为我们是要支持默认参数自定义,默认参数可是啥类型的都有,唯一的选择就是把这一过程打包成一个函数,然后这个函数就可以做为模板参数传过去了(敢不敢来个直接点的)。那么它大概长啥样呢

struct xLB_dfer {
	template<class TUP, int PARAM_COUNT> struct xLB_tir {
		static inline void go(TUP& tuple) {}
	};
};

template<class TUP> struct xLB_dfer::xLB_tir<TUP, 0> {
	static inline void go(TUP& tuple) {}
};

template<class TUP, class T, int Idx>
static inline void xLB_default_assign(TUP& tuple, const T& A) {
	std::get<Idx>(tuple) = A;
}

template<int BaseIdx, class TUP, class Idxer, class...T>
struct xLB_setdp {};

template<int BaseIdx, class TUP, int...Idxs, class...T>
struct xLB_setdp<BaseIdx, TUP, xLB_idxer<Idxs...>, T...> {
	static inline void go(TUP& tuple, T...DA) {
		xLB_each { 
			(xLB_default_assign<TUP, T, BaseIdx+Idxs>(tuple,DA),1)...
		};
	}
};

template<class TUP, class...T>
static inline void xLB_set_default_param(TUP& tuple, T...DA) {
	using idxer_t = typename xLB_toidxer<T...>::type;
		xLB_setdp<std::tuple_size<TUP>::value - sizeof...(T), TUP, idxer_t, T...>
			::go(tuple, DA...);
}


又是一堆模板,看烦了没有,先看看怎么自定义一个设置函数

struct My_dfer : public xLB_dfer {};
template<class TUP>
	struct My_dfer::xLB_tir<TUP, 1> {
		static inline void go(TUP& tuple) {
			//std::get<0>(tuple) = 9999;
			xLB_set_default_param(tuple, 8888);
		}
	};


这看起来还差不多,函数过程中的那两句是相同功能的,提供xLB_set_default_param是为了方便代码编写,畅想一下,用一个宏(支持不定参数),上面的代码就会变得非常直观。

从这个设置函数的编写,可以猜到其它的自定义支持过程是怎么样的,没错,跟这个几乎是一模一样,都是从xLB提供的默认类型继承,并提供特化函数。特化类型全部是以xLB_tir命名,其执行函数的名称都叫go。

再来看两个自定义,一个是类型,另一个是从Lua中提取函数参数

struct My_vter : public xLB_vter {};
template<> struct My_vter::xLB_tir<clsA*> { using type = clsA*; };

struct My_lver : public xLB_lver {};
template<int BaseIdx, int idx, class TUP>
	struct My_lver::xLB_tir<BaseIdx, idx, TUP, clsA*> {
		static inline void go(lua_State* L, TUP& tuple, int top) {
			if (idx+BaseIdx <= top) {
				auto wrap = reinterpret_cast<xLB_ludwrap<clsA>*>(lua_touserdata(L, idx+BaseIdx));
				auto obj = wrap->ptr(); assert(obj != nullptr);
				std::get<idx>(tuple) = obj;
			}
		}
	};


代码

xlb.h

#ifndef _XLB_H
#define _XLB_H

#include <iostream>
#include <vector>
#include <assert.h>
#include <cstring>
#include <tuple>
#include <memory>
#include <type_traits>
using namespace std;

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
} // lua header files

/*---------------------------------------------------------------------------
predeclare
-----------------------------------------------------------------------------*/
template<typename T> struct xLB_xotrait;
template<typename T> struct xLB_function;
template<typename T> struct xLB_xobase;


// tir (Type Information Replenish)
/*---------------------------------------------------------------------------
xLB_ludwrap : light user data wrapp as user data
-----------------------------------------------------------------------------*/
/* @struct xLB_ludwrap
 * This template used to wrapper lightuserdata as userdata, and then we can
 * set metatable on its. It's instance life managered by C++ not by Lua. */
template<typename T> struct xLB_ludwrap {
	T* ptr(){ return __ptr; }
	T* operator->() { return __ptr; }
	xLB_ludwrap(T* ptr, bool del=false) : __ptr(ptr), __del(del) {}
	virtual ~xLB_ludwrap() { if (__del) { delete __ptr; } }
protected:
	T* __ptr; /**< real object */
	bool __del; /**< delete __ptr when xLB_ludwrap was release */
}; // end of xLB_ludwrap

/*---------------------------------------------------------------------------
xLB_creatidxer
-----------------------------------------------------------------------------*/
template<int...> struct xLB_idxer{}; 
template<int...RPI> using xLB_rpi = xLB_idxer<RPI...>; // xLB_idxer alias

template<int, class Idxer, int> 
	struct xLB_creatidxer;

template<int I, int...Idxs, int RM>
	struct xLB_creatidxer<I, xLB_idxer<Idxs...>, RM> {
		using type = typename 
			xLB_creatidxer<I+1, xLB_idxer<Idxs..., I>, RM-1>::type;
	};

template<int I, int...Idxs>
	struct xLB_creatidxer<I, xLB_idxer<Idxs...>, 0> {
		typedef xLB_idxer<Idxs...> type;
	};

template<typename ...Types> 
	struct xLB_toidxer : 
		xLB_creatidxer<0, xLB_idxer<>, sizeof...(Types)> {};

/*---------------------------------------------------------------------------
xLB_return_void
-----------------------------------------------------------------------------*/
template<typename Tx> struct xLB_return_void {
		static const bool value = true;
	};

template<typename Tx, class R, class ...A> 
	struct xLB_return_void<R (Tx::*)(A...)> {
		static const bool value = std::is_void<R>::value;
	};

template<class R, class ...A>
 struct xLB_return_void<R (*)(A...)> {
	 static const bool value = std::is_void<R>::value;
 };


/*---------------------------------------------------------------------------
xLB_each
-----------------------------------------------------------------------------*/
struct xLB_each{ template<class ...T> xLB_each(T...) {} };

/*---------------------------------------------------------------------------
xLB_dfer
function default parameters provider
-----------------------------------------------------------------------------*/
struct xLB_dfer {
	template<class TUP, int PARAM_COUNT> struct xLB_tir {
		static inline void go(TUP& tuple) {}
	};
};

template<class TUP> struct xLB_dfer::xLB_tir<TUP, 0> {
	static inline void go(TUP& tuple) {}
};

template<class TUP, class T, int Idx>
static inline void xLB_default_assign(TUP& tuple, const T& A) {
	std::get<Idx>(tuple) = A;
}

template<int BaseIdx, class TUP, class Idxer, class...T>
struct xLB_setdp {};

template<int BaseIdx, class TUP, int...Idxs, class...T>
struct xLB_setdp<BaseIdx, TUP, xLB_idxer<Idxs...>, T...> {
	static inline void go(TUP& tuple, T...DA) {
		xLB_each { 
			(xLB_default_assign<TUP, T, BaseIdx+Idxs>(tuple,DA),1)...
		};
	}
};

template<class TUP, class...T>
static inline void xLB_set_default_param(TUP& tuple, T...DA) {
	using idxer_t = typename xLB_toidxer<T...>::type;
		xLB_setdp<std::tuple_size<TUP>::value - sizeof...(T), TUP, idxer_t, T...>
			::go(tuple, DA...);
}

/*---------------------------------------------------------------------------
xLB_lver
-----------------------------------------------------------------------------*/
struct xLB_lver {
	template<int BaseIdx, int idx, class TUP, class V> struct xLB_tir {
			static inline void go(lua_State* L, TUP& tuple, int top) {
				printf("Warning: xLB_lver(%s) not implemented.
", typeid(V).name());
			}
		};
};

template<int BaseIdx, int idx, class TUP>
struct xLB_lver::xLB_tir<BaseIdx, idx, TUP, int> {
	static inline void go(lua_State* L, TUP& tuple, int top) {
		if (idx+BaseIdx <= top) {
			std::get<idx>(tuple) = lua_tointeger(L, idx+BaseIdx);
		}
	}
};

template<int BaseIdx, int idx, class TUP>
struct xLB_lver::xLB_tir<BaseIdx, idx, TUP, double> {
	static inline void go(lua_State* L, TUP& tuple, int top) {
		if (idx+BaseIdx <= top) {
			std::get<idx>(tuple) = lua_tonumber(L, idx+BaseIdx);
		}
	}
};

/*---------------------------------------------------------------------------
xLB_fver
-----------------------------------------------------------------------------*/
template<int BaseIdx, class LVER, class IDXER, class...TA>
	struct xLB_fver {};

template<int BaseIdx, class LVER, int...idxs, class...TA>
	struct xLB_fver<BaseIdx, LVER, xLB_idxer<idxs...>, TA...> {
		using TUP = std::tuple<TA...>;
		static inline void go(lua_State* L, TUP& tuple) {
			xLB_each{ (LVER::template 
					xLB_tir<BaseIdx,idxs,TUP,TA>::go(L, tuple, lua_gettop(L)),1)... };
		}
	};

/*---------------------------------------------------------------------------
xLB_pper
push data(parameters of function) into lua_State
-----------------------------------------------------------------------------*/
struct xLB_pper {
	template<typename T> struct xLB_tir {
		static inline void go(lua_State* L, T tuple_val, int& return_count) {
			lua_pushnumber(L, tuple_val); ++return_count; 
		}
	};
};

template<> struct xLB_pper::xLB_tir<const char*> {
	static inline void go(lua_State* L, const char* tuple_val, int& return_count) { 
		lua_pushstring(L, tuple_val); ++return_count; 
	}
};

template<> struct xLB_pper::xLB_tir<double> { 
	static inline void go(lua_State* L, double tuple_val, int& return_count) { 
		lua_pushnumber(L, tuple_val); ++return_count; 
	}
};

template<> struct xLB_pper::xLB_tir<long> { 
	static inline void go(lua_State* L, long tuple_val, int& return_count) { 
		lua_pushnumber(L, tuple_val); ++return_count; 
	}
};

template<> struct xLB_pper::xLB_tir<bool> { 
	static inline void go(lua_State* L, bool tuple_val, int& return_count) { 
		lua_pushnumber(L, tuple_val); ++return_count; 
	}
};

/*---------------------------------------------------------------------------
xLB_pter
push addition parameters of function into lua_State
-----------------------------------------------------------------------------*/
struct xLB_pter { template<class,class,class> struct xLB_tir {}; };

template<int...RPI,class...A,class PPER> 
	struct xLB_pter::xLB_tir<xLB_idxer<RPI...>,std::tuple<A...>,PPER> {
		static inline void go(lua_State* L, std::tuple<A...>& tuple, int& return_count) {
			xLB_each{ (PPER::template xLB_tir<
					typename std::tuple_element<RPI, std::tuple<A...>>::type>
				::go(L, std::get<RPI>(tuple), return_count), 1)... 
			};
		}
	};

/*---------------------------------------------------------------------------
xLB_rner
push result of function into lua_State
-----------------------------------------------------------------------------*/
struct xLB_rner {
	template<class R, class PPER> struct xLB_tir {
		static inline void go(lua_State* L, const R& result_of_function, int& return_count) {
			PPER::template xLB_tir<R>::go(L, result_of_function, return_count);
		}
	};
};

/*---------------------------------------------------------------------------
xLB_vper
change type of value according to parameter's type for calling function
-----------------------------------------------------------------------------*/
struct xLB_vper {
	template<class To, class From> struct xLB_tir {
		static inline const To& go(const From& tuple_val) { return tuple_val; } 
	};
};

template<class T>struct xLB_vper::xLB_tir<T*, T*> {
	static inline T* go(T* tuple_val) { return tuple_val; } 
};

template<>struct xLB_vper::xLB_tir<int&, int> {
	static inline int& go(int& tuple_val) { return tuple_val; } 
};

template<>struct xLB_vper::xLB_tir<int*, int> {
	static inline int* go(int& tuple_val) { return &tuple_val; } 
};

/*---------------------------------------------------------------------------
xLB_vter
decide type of value for saving data come from lua_State
-----------------------------------------------------------------------------*/
struct xLB_vter {
	template<class PARAM_TYPE> struct xLB_tir { 
		using type = PARAM_TYPE;
		static_assert(std::is_pod<PARAM_TYPE>::value, "Warning: xLB_vter no implement
"); 
	};
};

template<class PARAM_TYPE> struct xLB_vter::xLB_tir<PARAM_TYPE&> {
	using type = typename xLB_vter::xLB_tir<PARAM_TYPE>::type;
};

template<> struct xLB_vter::xLB_tir<int*> { using type = int; };
template<> struct xLB_vter::xLB_tir<double*> { using type = double; };

/*---------------------------------------------------------------------------
xLB_caler
-----------------------------------------------------------------------------*/
struct xLB_caler {
	template<class FT,class,class,class...A> struct xLB_tir {};
};

template<class R, class T, class VPER, class...A, class...B, int...idxs> 
	struct xLB_caler::xLB_tir<R (T::*)(A...), xLB_idxer<idxs...>, VPER, B...> {
		static inline R go(T* obj, R (T::*f)(A...), std::tuple<B...>& tuple) {
			return (obj->*f)(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
		}
	};

template<class T, class VPER, class...A, class...B, int...idxs> 
	struct xLB_caler::xLB_tir<void (T::*)(A...), xLB_idxer<idxs...>, VPER, B...> {
		static inline void go(T* obj, void (T::*f)(A...), std::tuple<B...>& tuple) {
			(obj->*f)(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
		}
	};

template<class VPER, class...A, class...B, int...idxs> 
	struct xLB_caler::xLB_tir<void (*)(A...), xLB_idxer<idxs...>, VPER, B...> {
		static inline void go(void (*f)(A...), std::tuple<B...>& tuple) {
			f(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
		}
	};

template<class R, class VPER, class...A, class...B, int...idxs> 
	struct xLB_caler::xLB_tir<R (*)(A...), xLB_idxer<idxs...>, VPER, B...> {
		static inline R go(R (*f)(A...), std::tuple<B...>& tuple) {
			return f(VPER::template xLB_tir<A,B>::go(std::get<idxs>(tuple))...);
		}
	};
/*---------------------------------------------------------------------------
xLB_adter
-----------------------------------------------------------------------------*/
template<class R, class T, class F, F f, int DFCOUNT, class DFER, class RPIdxer,
	class PPER, class RNER, class PTER, class VTER, class LVER, class VPER, class...A>
int xLB_adter(lua_State* L) {
	using wrap_t = xLB_ludwrap<T>;
	using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
	using idxer_t = typename xLB_toidxer<A...>::type;
	tuple_t tuple;
	DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
	xLB_fver<2,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
		::go(L, tuple);
	auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
	assert(wrap != nullptr);
	auto obj = wrap->ptr(); assert(obj != nullptr);
	R r = xLB_caler::template xLB_tir<F,idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
		::go(obj, f, tuple);
	int rcnt = 0;
	RNER::template xLB_tir<R,PPER>::go(L,r,rcnt);
	PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
		::go(L, tuple, rcnt);
	return rcnt;
}

/*---------------------------------------------------------------------------
xLB_adter_void
-----------------------------------------------------------------------------*/
template<class T, class F, F f, int DFCOUNT, class DFER, class RPIdxer,
	class PPER, class RNER, class PTER, class VTER, class LVER, class VPER, class...A>
int xLB_adter_void(lua_State* L) {
	using wrap_t = xLB_ludwrap<T>;
	using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
	using idxer_t = typename xLB_toidxer<A...>::type;
	tuple_t tuple;
	DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
	xLB_fver<2,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
		::go(L, tuple);
	auto wrap = reinterpret_cast<wrap_t*>(lua_touserdata(L, 1));
	assert(wrap != nullptr);
	auto obj = wrap->ptr(); assert(obj != nullptr);
	xLB_caler::template xLB_tir<F,idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
		::go(obj, f, tuple);
	int rcnt = 0;
	PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
		::go(L, tuple, rcnt);
	return rcnt;
}

/*---------------------------------------------------------------------------
xLB_CFunc
-----------------------------------------------------------------------------*/
struct xLB_CFunc {
	template<class F, F f, bool, int DFCOUNT, class DFER,
			class RPIdxer, class PPER, class RNER, 
			class PTER, class VTER, class LVER, class VPER> struct xLB_tir {};

	template<class FT, FT f,
			int DFCOUNT=0,
			class DFER=xLB_dfer,
			class RPIdxer=xLB_idxer<>, 
			class PPER=xLB_pper,
			class RNER=xLB_rner,
			class PTER=xLB_pter,
			class VTER=xLB_vter, 
			class LVER=xLB_lver, 
			class VPER=xLB_vper
		> static inline lua_CFunction b() {
				return xLB_CFunc::template xLB_tir<
						FT,f,xLB_return_void<FT>::value,DFCOUNT,DFER,
						RPIdxer,PPER,RNER,PTER,VTER,LVER,VPER
					>::func;
			}
};

template<class...A, void (*f)(A...), int DFCOUNT, class DFER,
		class RPIdxer, class PPER, class RNER, 
		class PTER, class VTER, class LVER, class VPER
> struct xLB_CFunc::xLB_tir<void (*)(A...), f, true, DFCOUNT, DFER, RPIdxer, PPER, RNER, PTER, VTER, LVER, VPER> {
		static int func(lua_State* L) {
			using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
			using idxer_t = typename xLB_toidxer<A...>::type;
			tuple_t tuple;
			DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
			xLB_fver<1,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
				::go(L, tuple);
			xLB_caler::template xLB_tir<decltype(f),idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
				::go(f, tuple);
			int rcnt = 0;
			PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
				::go(L, tuple, rcnt);
			return rcnt;
		};
	};

template<class...A, class R, R (*f)(A...), int DFCOUNT, class DFER,
		class RPIdxer, class PPER, class RNER, 
		class PTER, class VTER, class LVER, class VPER
> struct xLB_CFunc::xLB_tir<R (*)(A...), f, false, DFCOUNT, DFER, RPIdxer, PPER, RNER, PTER, VTER, LVER, VPER> {
		static int func(lua_State* L) {
			using tuple_t = std::tuple<typename VTER::template xLB_tir<A>::type...>;
			using idxer_t = typename xLB_toidxer<A...>::type;
			tuple_t tuple;
			DFER::template xLB_tir<tuple_t, DFCOUNT>::go(tuple);
			xLB_fver<1,LVER,idxer_t,typename VTER::template xLB_tir<A>::type...>
				::go(L, tuple);
			R r = xLB_caler::template xLB_tir<decltype(f),idxer_t,VPER,typename VTER::template xLB_tir<A>::type...>
				::go(f, tuple);
			int rcnt = 0;
			RNER::template xLB_tir<R,PPER>::go(L,r,rcnt);
			PTER::template xLB_tir<RPIdxer,tuple_t,PPER>
				::go(L, tuple, rcnt);
			return rcnt;
		};
	};

/*---------------------------------------------------------------------------
xLB_agent
-----------------------------------------------------------------------------*/
template<class Tx,Tx,bool,int,class,class,class,class,class,class,class,class> 
	struct xLB_agent {};

template<class Tx, class R, class ...A, R (Tx::*f)(A...), int DFCOUNT, class DFER, int...RPI,
		class PPER, class RNER, class PTER, class VTER, class LVER, class VPER>
	struct xLB_agent<R (Tx::*)(A...), f, false, DFCOUNT, DFER, xLB_idxer<RPI...>,
			PPER,RNER,PTER,VTER,LVER,VPER> {
		static inline void b(const char fn[]) { 
			xLB_xobase<Tx>::regfunc(fn,
					xLB_adter<R, Tx, R (Tx::*)(A...), f, DFCOUNT, DFER, xLB_idxer<RPI...>,
						PPER,RNER,PTER,VTER,LVER,VPER, A...>);
		}
	};

template<class Tx, class ...A, void (Tx::*f)(A...), int DFCOUNT, class DFER, int...RPI,
		class PPER, class RNER, class PTER, class VTER, class LVER, class VPER>
	struct xLB_agent<void (Tx::*)(A...), f, true, DFCOUNT, DFER, xLB_idxer<RPI...>,
			PPER,RNER,PTER,VTER,LVER,VPER> {
		static inline void b(const char fn[]) {
			xLB_xobase<Tx>::regfunc(fn,
					xLB_adter_void<Tx, void (Tx::*)(A...), f, DFCOUNT, DFER, xLB_idxer<RPI...>,
							PPER,RNER,PTER,VTER,LVER,VPER, A...>);
		}
	};


/*---------------------------------------------------------------------------
xlb function
-----------------------------------------------------------------------------*/
#define luaL_reg luaL_Reg

/** This function create metatable with lua api and set __index and metatable 
 * to itself and make it have key weak feature. */
void xLB_newmetatable(lua_State* L, const char* LibName, luaL_Reg* Lreg);

/** This function set metatable named LibName to userdata at top of stack. */
void xLB_userdata(lua_State* L, const char* LibName, lua_Number N = 0);


/*---------------------------------------------------------------------------
lua userdata and C++ object
-----------------------------------------------------------------------------*/
/** if the object specify by index is userdata then
 * 1. if it is instance of type xLB_ludwrap<T> then get T* address from it;
 * 2. if it is derived from T* then get T* from userdata;
 * otherwise return nullptr; */
template<typename T, const char meta[]>
T* xLB_getuserdata(lua_State* L, int index, xLB_ludwrap<T>** pWp = 0) {
	using w_t = xLB_ludwrap<T>;
	T* r = 0;
	if (lua_isuserdata(L, index)) {
		auto wp = reinterpret_cast<w_t*>(luaL_checkudata(L, index, meta));
		//auto wp = reinterpret_cast<w_t*>(lua_touserdata(L, index));
		if (wp) { r = wp->ptr(); if (pWp) { *pWp = wp; } }
	} //else { nb_warn(true, "userdata expected"); }
	return r;
}

/* Wrap xo as Lua ud, and Lua do not charge object's life. */
template<typename T>
void xLB_wrapxo(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj/*,false*/);
	xLB_userdata(L, xLB_xotrait<T>::meta_name, 0);
}

template<typename T, const char meta[]>
void xLB_objasud(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	auto place = (w_t*)(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj, true);
	xLB_userdata(L, meta, 0);
}

/* Wrap xo as Lua ud, means Lua charge object's life. */
template<typename T>
void xLB_xoasud(lua_State* L, T* obj) {
	typedef xLB_ludwrap<T> w_t;
	w_t* place = static_cast<w_t*>(lua_newuserdata(L, sizeof(w_t)));
	new(place) w_t(obj, true);
	xLB_userdata(L, xLB_xotrait<T>::meta_name, 0);
}

template<typename T, const char meta[]>
int xLB_gcobj(lua_State* L) {
	xLB_ludwrap<T>* wp = 0;
	xLB_getuserdata<T, meta>(L, 1, &wp);
	if (wp) { wp->~xLB_ludwrap<T>();}
	return 0;
}

template<typename T, typename...A>
T* xLB_newxo(lua_State* L, A...arg_metas) {
	T* pobj = new T(arg_metas...);
	xLB_objasud<T, xLB_xotrait<T>::meta_name>(L, pobj);
	return pobj;
}

template<typename T>
int xLB_gcxo(lua_State* L) {
	xLB_ludwrap<T>* wp = nullptr;
	xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, 1, &wp);
	if (wp) { wp->~xLB_ludwrap<T>(); }
	return 0;
}

/*---------------------------------------------------------------------------
xLB binder
-----------------------------------------------------------------------------*/
template<typename T>
	unique_ptr<xLB_xotrait<T>> xLB_newxobinder() {
		return unique_ptr<xLB_xotrait<T>>(new xLB_xotrait<T>());
	}

template<typename T>
	void xLB_bindxo(lua_State* L, const char* ns=nullptr) {
		xLB_xotrait<T>::reg(L, ns);
	}

template<typename T>
	void xLB_xoglobal(lua_State* L, T* obj, const char* name) {
		xLB_wrapxo(L, obj);
		lua_setglobal(L, name);
	}

/*---------------------------------------------------------------------------
xLB ns table
-----------------------------------------------------------------------------*/
#define xLB_pushtable(L, tbl, name, ns) tbl().reg(L, name, ns);
void xLB_newnstable(lua_State* L, const char* name, const char* ns);
void xLB_newnstable(lua_State* L, const char* tn, int index);
//void xLB_getnstable(lua_State* L, const char* name, const char* ns);

/*---------------------------------------------------------------------------
xo macro
-----------------------------------------------------------------------------*/
#define xLB_xoinitmember(xo_t) 
template<> const char xLB_xobase<xo_t>::meta_name[]="xLB_"#xo_t; 
template<> const char xLB_xobase<xo_t>::type_name[]=#xo_t; 
template<> xLB_pchars xLB_xobase<xo_t>::super_name_list=xLB_pchars(); 
template<> std::vector<luaL_reg> xLB_xobase<xo_t>::rg_meta={{nullptr,nullptr}}; 
template<> std::vector<luaL_reg> xLB_xobase<xo_t>::rg_type={{nullptr,nullptr}}; 

#define xLB_xodefineobj(xo_t) xLB_xotrait<xo_t> xLB_xo##xo_t; 

#define xLB_xodefine(xo_t) 
xLB_xoinitmember(xo_t) 
xLB_xodefineobj(xo_t) 

#define xLB_xodeclare(xo_t) 
template<> struct xLB_xotrait<xo_t> : public xLB_xobase<xo_t> 

/*---------------------------------------------------------------------------
xLB_method
-----------------------------------------------------------------------------*/
template<typename T> struct xLB_method {
	using type = int (*)(lua_State*, T*);
};

template<typename R, typename T, typename... A>
struct xLB_method<R (T::*)(A...) > {
	using type = R(T::*)(A...);
};

template<typename R, typename T, typename... A>
struct xLB_method<R (T::*)(A...) const > {
	using type = R(T::*)(A...) const;
};

template<typename T>
T* xLB_getxo(lua_State* L, int index) {
	return xLB_getuserdata<T, xLB_xotrait<T>::meta_name>(L, index);
}

template<typename T, typename xLB_method<T>::type f>
int xLB_xomethod(lua_State* L) {
	int rc = 0;
	T* obj = xLB_getxo<T>(L, 1);
	if (obj) rc = f(L, obj);
	return rc;
}

/*---------------------------------------------------------------------------
xLB_xotrait
-----------------------------------------------------------------------------*/
template<typename T> struct xLB_xotrait{ static char meta[]; };

typedef std::vector<const char*> xLB_pchars;
int xLB_search(lua_State* L, const char* method_name, const xLB_pchars& nlst);
int xLB_rawsearch(lua_State* L, const char* method_name, const char* meta_name);

/*---------------------------------------------------------------------------
xLB_xobase
-----------------------------------------------------------------------------*/
template<typename X>
struct xLB_xobase {
	typedef X T;
	typedef xLB_xobase self_t;
	typedef xLB_xobase* this_t;
	typedef xLB_xotrait<T> trait_t;
	typedef std::vector<luaL_reg> regs_t;
	static const char meta_name[];
	static const char type_name[];
	static xLB_pchars super_name_list;
	static regs_t rg_meta;
	static regs_t rg_type;
	//virtual ~xLB_xobase() = delete;

	static inline void regfunc(const char fn[], lua_CFunction f) {
		auto it = begin(rg_meta);
		rg_meta.insert(it, {fn,f});
	}

	static int index_implement(lua_State* L) { //__index(t,k)
		auto method_name = luaL_optlstring(L, 2, "", nullptr);
		int nFound = xLB_rawsearch(L, method_name, meta_name);
		if (!nFound) {
			nFound = xLB_search(L, method_name, super_name_list);
		}
		return nFound;
	}

	static void newxometatable(lua_State* L) {
		luaL_newmetatable(L, trait_t::meta_name);
		lua_pushstring(L, "__index");
		lua_pushcfunction(L, index_implement);
		lua_rawset(L, -3);
		// set metatable.metatable to itself
		lua_pushvalue(L, -1);
		lua_setmetatable(L, -2);
		luaL_setfuncs(L, &rg_meta[0], 0);
		lua_pop(L, 1); // pop metatable
	}

	template<class SUPER_XO> static void super() { 
		super_name_list.push_back(xLB_xotrait<SUPER_XO>::meta_name); 
	}

	template<lua_CFunction f> static void c(const char fn[]="new") { 
		auto it = begin(rg_type);
		rg_type.insert(it, {fn,f});
	}

	static void d() { b<xLB_gcxo<T>>("__gc"); }

	template<typename xLB_method<T>::type f> static void b(const char fn[]) { 
			regfunc(fn, xLB_xomethod<T, f>);
		}

	template<lua_CFunction f> static void b(const char fn[]) { 
			regfunc(fn, f);
		}

	template<class FT, FT f, 
		int DFCOUNT = 0,
		class DFER=xLB_dfer,
		class RPIs=xLB_idxer<>, 
		class PPER=xLB_pper,
		class RNER=xLB_rner,
		class PTER=xLB_pter,
		class VTER=xLB_vter, 
		class LVER=xLB_lver, 
		class VPER=xLB_vper> 
	static void bx(const char fn[]) {
		xLB_agent<FT, f, xLB_return_void<FT>::value, DFCOUNT, DFER, RPIs,
				PPER,RNER,PTER,VTER,LVER,VPER
		>::b(fn);
	}

	static void reg(lua_State* L, const char* ns = nullptr) {
		if (1 < rg_meta.size()) { newxometatable(L); }
		if (1 < rg_type.size()) {
			luaL_newlib(L, &rg_type[0]);
			if (ns && strlen(ns)) {
				lua_getglobal(L, ns);
				if (LUA_TTABLE != lua_type(L, -1)) {
					lua_pop(L, 1);
					lua_newtable(L);
					lua_setglobal(L, ns);
					lua_getglobal(L, ns);
				}
				lua_pushstring(L, trait_t::type_name);
				lua_pushvalue(L, -3);
				lua_rawset(L, -3);
				lua_pop(L, 2);
			}
		}
	}
}; // end of xLB_xobase

/*---------------------------------------------------------------------------
xLB_table
-----------------------------------------------------------------------------*/
template<typename X>
struct xLB_table {
	typedef X T;
	typedef xLB_table self_t;
	typedef xLB_table* this_t;
	typedef std::vector<luaL_reg> regs_t;
	virtual ~xLB_table() {}
	regs_t rg_table;
	template<lua_CFunction f> void c(const char fn[]) { 
		rg_table.push_back({fn,f});
	}
	template<lua_CFunction f>
		void b(const char fn[]) { 
			rg_table.push_back({fn,f});
		}
	void reg(lua_State* L, const char* tn, const char* ns = 0) {
		if (0 < rg_table.size()) {
			rg_table.push_back({nullptr,nullptr});
			luaL_newlib(L, &rg_table[0]);
			if (ns && strlen(ns)) {
				lua_getglobal(L, ns);
				int t = lua_type(L, -1);
				if (LUA_TNIL == t || LUA_TTABLE != t ) {
					lua_pop(L, 1);
					lua_newtable(L);
					lua_setglobal(L, ns);
					lua_getglobal(L, ns);
				}
				lua_pushstring(L, tn);
				lua_pushvalue(L, -3);
				lua_rawset(L, -3);
				lua_pop(L, 2);
			}
		}
	}
	void reg(lua_State* L, const char* tn, int index = 0) {
		if (0 < rg_table.size()) {
			rg_table.push_back({nullptr,nullptr});
			lua_pushstring(L, tn);
			luaL_newlib(L, &rg_table[0]);
			if (index < 0) { index-=2; }
			if (index) { lua_rawset(L, index); }
		}
	}
}; // end of xLB_table

#endif // end of __XLB_H__


xlb.cpp

#include <ns/xlb.h>

/*---------------------------------------------------------------------------
lux_
-----------------------------------------------------------------------------*/
void xLB_newmetatable(lua_State* L, const char* LibName, luaL_Reg* Lreg) {
	luaL_newmetatable(L, LibName);
	lua_pushstring(L, "__index");
	lua_pushvalue(L, -2);
	lua_rawset(L, -3);
	// set metatable to "key" weak table
	//lua_pushstring(L, "__mode");
	//lua_pushstring(L, "k");
	//lua_rawset(L, -3);
	// set metatable.metatable to itself
	lua_pushvalue(L, -1);
	lua_setmetatable(L, -2);
	//luaL_register(L, nullptr, Lreg);
	luaL_setfuncs(L, Lreg, 0/*no upvalue for funcs to share*/);
	lua_pop(L, 1); // pop metatable
}

int xLB_search(lua_State* L, 
const char* method_name, const xLB_pchars& nlst) {
	int nFound = 0;
	for (auto meta_name : nlst) {
		lua_getfield(L, LUA_REGISTRYINDEX, meta_name);
		if (!lua_istable(L, -1)) { 
			//nb_warn(true, "%s not registered", meta_name); 
			return 0;
		} else {
			lua_pushstring(L, method_name);
			lua_gettable(L, -2);
			lua_replace(L, -2);
			nFound = (lua_isnil(L, -1) ? 0 : 1);
			if (nFound) break;
		}
	}
	return nFound;
}

int xLB_rawsearch(lua_State* L, 
const char* method_name, const char* meta_name) {
	//nb_warn(true, "search: %s in %s", method_name, meta_name);
	lua_getfield(L, LUA_REGISTRYINDEX, meta_name);
	if (!lua_istable(L, -1)) { 
		//nb_warn(true, "%s not registered", meta_name); 
		return 0;
	} else {
		lua_pushstring(L, method_name);
		lua_rawget(L, -2);
		lua_replace(L, -2);
		return (lua_isnil(L, -1) ? 0 : 1);
	}
}

void xLB_userdata(lua_State* L, const char* LibName, lua_Number N) {
	// s: 1(ud)
	//int inew = 
		luaL_newmetatable(L, LibName); // s: 1(ud), 2(metatable)
	//nb_warn(inew, "xLB-Error: %d %s", inew, LibName);
	lua_setmetatable(L, -2); // userdata.metatable = metatable
}


void xLB_newnstable(lua_State* L, const char* name, const char* ns) {
	lua_getglobal(L, ns);
	if (LUA_TTABLE == lua_type(L, -1)) {
		lua_pushstring(L, name);
		lua_newtable(L); 
		lua_rawset(L, -3);
	}
	lua_pop(L, 1);
}

void xLB_newnstable(lua_State* L, const char* tn, int index) {
	lua_pushstring(L, tn);
	lua_newtable(L);
	if (index < 0) { index-=2; }
	lua_rawset(L, index);
}

/*
void xLB_getnstable(lua_State* L, const char* name, const char* ns) {
	lua_getglobal(L, ns);
	lua_pushlstring(L, name, strlen(name));
	lua_rawget(L, -2);
	lua_insert(L, -2);
	lua_pop(L, 1);
}
*/


测试的一段代码

xlbinder.h

#ifndef _XLBINDER_H
#define _XLBINDER_H

#include <ns/xlb.h>
#include <type_traits>


struct clsB {
	void b() { printf("base class clsB::b() method called
"); }
};

struct clsA : public clsB {
	int Add(int a, int& b);
	int Del(int* a);
	int Modify(int& a);
	void NoReturn(int a);
	void Complex(clsA* pa);
	int x = 999;
}; // end of clsA

xLB_xodeclare(clsB) {
	xLB_xotrait() {
		bx<decltype(&clsB::b), &clsB::b>("b");
	}
};

struct My_vter : public xLB_vter {};
template<> struct My_vter::xLB_tir<clsA*> { using type = clsA*; };

struct My_lver : public xLB_lver {};
template<int BaseIdx, int idx, class TUP>
	struct My_lver::xLB_tir<BaseIdx, idx, TUP, clsA*> {
		static inline void go(lua_State* L, TUP& tuple, int top) {
			if (idx+BaseIdx <= top) {
				auto wrap = reinterpret_cast<xLB_ludwrap<clsA>*>(lua_touserdata(L, idx+BaseIdx));
				auto obj = wrap->ptr(); assert(obj != nullptr);
				std::get<idx>(tuple) = obj;
			}
		}
	};

struct My_dfer : public xLB_dfer {};
template<class TUP>
	struct My_dfer::xLB_tir<TUP, 1> {
		static inline void go(TUP& tuple) {
			//std::get<0>(tuple) = 9999;
			xLB_set_default_param(tuple, 8888);
		}
	};


xLB_xodeclare(clsA) {
	xLB_xotrait() {
		super<clsB>();
		bx<decltype(&clsA::Add), &clsA::Add, 0, xLB_dfer, xLB_idxer<1,0>>("Add");
		bx<decltype(&clsA::NoReturn), &clsA::NoReturn, 1, My_dfer, xLB_idxer<0>>("NoReturn");
		bx<decltype(&clsA::Complex), &clsA::Complex, 0, xLB_dfer, xLB_idxer<>,
			xLB_pper,
			xLB_rner,
			xLB_pter,
			My_vter, //xLB_vter, 
			My_lver, //xLB_lver, 
			xLB_vper
				>("Complex");
	}
};

struct mytype {
	int a;
};

void foo(int a);
int g(int a);
int h(clsA* a);

#endif


xlbinder.cpp

#include "xlbinder.h"

//----------------------------------------------------------------------
int clsA::Add(int a, int& b) { 
	printf("clsA::Add(%d,%d):%d called
", a,b,a+b);
	b+=123;
	return a+b; 
}
int clsA::Del(int* a) { printf("obj:Del called: %d
", *a); return *a = 2; };
int clsA::Modify(int& a) { return a*=2; }
void clsA::NoReturn(int a) { printf("obj:NoReturn called: %d
", a*3); }
void clsA::Complex(clsA* pa) { printf("Complex %d
", pa->x); }

//----------------------------------------------------------------------
void foo(int a) { printf("foo called: %d
", a); }
int g(int a) { printf("g called: %d
", a); return a+2; }
int h(clsA* a) { printf("h called: %d
", a->x); return 0; }


//----------------------------------------------------------------------
xLB_xodefine(clsA);
xLB_xodefine(clsB);
//----------------------------------------------------------------------------


//----------------------------------------------------------------------------
int main() {
	std::cout << "xLB test ... 
";
	auto L = luaL_newstate();
	luaL_openlibs(L);
	xLB_bindxo<clsB>(L);
	xLB_bindxo<clsA>(L);
	clsA obj;
	obj.x = 99;
	xLB_xoglobal<clsA>(L, &obj, "obj");
	luaL_dostring(L, "print('Lua{');");
	luaL_dostring(L, "print('getmetatable(obj)={');");
	luaL_dostring(L, "for k,v in pairs(getmetatable(obj)) do print('  ' .. k .. '=' .. tostring(v)); end");
	luaL_dostring(L, "print('}');");
	luaL_dostring(L, "print(obj:Complex(obj));");
	luaL_dostring(L, "print(obj:Add(99,2));");
	
	luaL_dostring(L, "x = obj:NoReturn(8); ");
	luaL_dostring(L, "print('obj:NoReturn(8)=' .. tostring(x));");
	luaL_dostring(L, "x = obj:NoReturn(); ");
	luaL_dostring(L, "print('obj:NoReturn(default_param)=' .. tostring(x));");
	
	//---
	lua_register(L, "foo", (xLB_CFunc::b<decltype(&foo), &foo, 1, My_dfer>()));
	luaL_dostring(L, "x = foo(1901);");
	luaL_dostring(L, "print('foo(1901)=' .. tostring(x));");
	luaL_dostring(L, "x = foo();");
	luaL_dostring(L, "print('foo(default_param)=' .. tostring(x));");

	lua_register(L, "g", (xLB_CFunc::b<decltype(&g), &g, 0, xLB_dfer, xLB_idxer<0>>()));
	luaL_dostring(L, "print(g(1999));");

	lua_register(L, "h", (
			xLB_CFunc::b<decltype(&h), // type of function
			&h, // pointer of function
			0, // count of default parameters for function
			xLB_dfer, // setter for default parameters for function
			xLB_idxer<>, // index of parameters for return
			xLB_pper, // how each value pushed into Lua
			xLB_rner, // how the result of function pushed into Lua
			xLB_pter, // how those parameters after function calling pushed into Lua
			My_vter, // decide what type of value for saving the function parameters
			My_lver, // how the value load from Lua
			xLB_vper // make values as function's parameters
			>()));
	luaL_dostring(L, "h(obj);");
	luaL_dostring(L, "obj:b()"); // call base class method

	lua_close(L);
	printf("}
");
	return 0;
}

输出结果:

xLB test ...
Lua{
getmetatable(obj)={
  Add=function: 004094D0
  __index=function: 004096A0
  Complex=function: 00409214
  NoReturn=function: 00409300
}
Complex 99

clsA::Add(99,2):101 called
224     99      125
obj:NoReturn called: 24
obj:NoReturn(8)=8
obj:NoReturn called: 26664
obj:NoReturn(default_param)=8888
foo called: 1901
foo(1901)=nil
foo called: 8888
foo(default_param)=nil
g called: 1999
2001    1999
h called: 99
base class clsB::b() method called
}



原文地址:https://www.cnblogs.com/fuhaots2009/p/3503165.html