|
现在的C++设计,为了保证健壮性和复用性,特别是GP的流行,往往应用了大量的模板,容器,智能指针。但这对与LUA绑定来说绝对不是一个好消息,非常的烦琐。个人觉得,在第三方的绑定库里面,luabind和现代C++设计结合最好,也是灵活性最高的一个绑定库。 luabind确实很强大,但这里就不介绍一般应用了,doc中有详细的说明,使用也非常的简单。我主要介绍一下converter和policy,特别是policy,简直是luabind中的核武器,可以非常方便的让容器,迭代子与lua相结合。但遗憾的是,luabind的文档中并没有对自定义convert和policy做一个详细说明,那个converter的说明,牛头不对马嘴,sample中的any converter,更是无法编译。 我这里通过容器vector的应用来说明,怎么自定义convert和policy。 首先,我们来看这么一段代码:
void test1(const vector<string> &v)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
copy(v.begin(),v.end(),ostream_iterator<string>(cout,"\n"));
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
vector<string> test2()
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
vector<string> r;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
r.push_back("r");
r.push_back("g");
r.push_back("b");
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
return r;
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) void main() {
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
lua_State* L = lua_open();
luaL_openlibs(L);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
open(L);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
module(L)
[
def("test1", &test1),
def("test2", &test2)
];
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
luaL_dostring(L,"test1({\"1\",\"2\",\"3\"}) vec=test2() for k, v in ipairs(vec) do print(k..\":\"..v) end");
lua_close(L);
}
毫无疑问,调用这段lua代码,得不到任何正确的结果,甚至当你把vector<string>当参数传给lua,会得到you are trying to use an unregistered type的一个assert。因为luabind并不知道怎样去处理vector<string>这个东西。 最简单的做法,我们就是通过default_converter的特化,来实现容器的使用。luabind都是通过default_converter来把call_function的调用参数压入lua调用栈,所有的default_converter特化都可以在policy.hpp中找到。比如,将std::string入栈的特化convert就是:
template <>
struct default_converter<std::string>
: native_converter_base<std::string>
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
static int compute_score(lua_State* L, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return lua_type(L, index) == LUA_TSTRING ? 0 : -1;
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
std::string from(lua_State* L, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return std::string(lua_tostring(L, index), lua_strlen(L, index));
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
void to(lua_State* L, std::string const& value)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
lua_pushlstring(L, value.data(), value.size());
}
};
其中void to(lua_State* L, std::string const& value),是把string压入栈中。而from是将一个栈中数据转化为string,computer_score检查栈中数据类型是否符合。很简单,不是吗?那让我们来看看,我们的vector应该怎么写。
namespace luabind
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
template <class T>
struct default_converter<vector<T> >
: native_converter_base<vector<T> >
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
static int compute_score(lua_State* L, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return (lua_type(L, index) == LUA_TTABLE )? 0 : -1;
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
vector<T> from(lua_State* L, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
vector<T> container;
luabind::object tbl(from_stack(L, index));
for (luabind::iterator itr(tbl), end; itr != end; ++itr)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
boost::optional<T> v = object_cast_nothrow<T>(*itr);
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) if (v) {
container.push_back(*v);
}
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
return container;
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
void to(lua_State* L, vector<T> const& container)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
lua_createtable(L, container.size(), 0);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
luabind::object tbl(from_stack(L, -1));
int n = 0;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
for (vector<T>::const_iterator itr = container.begin(); itr != container.end(); ++itr)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
tbl[++n] = *itr;
}
}
};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template <class T>
struct default_converter<vector<T> const&>
: default_converter<vector<T> >
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {};
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
是不是很简单啊。:) 再运行上面那段代码。。就得到了我们想要的正确结果: ![](http://www.cppblog.com/images/cppblog_com/clane/2009010801.JPG) 至于luabind的policy,它就更强大了。我们来看看policy版本的容器,应该怎么来做。luabind/contain_policy.hpp就实现了容器的使用。代码如下
// Copyright (c) 2003 Daniel Wallin and Arvid Norberg
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
#ifndef LUABIND_CONTAINER_POLICY_HPP_INCLUDED
#define LUABIND_CONTAINER_POLICY_HPP_INCLUDED
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
#include <luabind/config.hpp>
#include <luabind/detail/policy.hpp>
#include <boost/mpl/apply_wrap.hpp>
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) namespace luabind { namespace detail {
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
namespace mpl = boost::mpl;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<class Policies>
struct container_converter_lua_to_cpp
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
template<class T>
T apply(lua_State* L, by_const_reference<T>, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
typedef typename T::value_type value_type;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
typedef typename find_conversion_policy<1, Policies>::type converter_policy;
typename mpl::apply_wrap2<converter_policy,value_type,lua_to_cpp>::type converter;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
T container;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
lua_pushnil(L);
while (lua_next(L, index))
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
container.push_back(converter.apply(L, LUABIND_DECORATE_TYPE(value_type), -1));
lua_pop(L, 1); // pop value
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
return container;
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<class T>
T apply(lua_State* L, by_value<T>, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return apply(L, by_const_reference<T>(), index);
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<class T>
static int match(lua_State* L, by_const_reference<T>, int index)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
if (lua_istable(L, index)) return 0; else return -1;
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<class T>
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) void converter_postcall(lua_State*, T, int) {}
};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<class Policies>
struct container_converter_cpp_to_lua
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
template<class T>
void apply(lua_State* L, const T& container)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
typedef typename T::value_type value_type;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
typedef typename find_conversion_policy<1, Policies>::type converter_policy;
typename mpl::apply_wrap2<converter_policy,value_type,lua_to_cpp>::type converter;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
lua_newtable(L);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
int index = 1;
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
for (typename T::const_iterator i = container.begin(); i != container.end(); ++i)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
converter.apply(L, *i);
lua_rawseti(L, -2, index);
++index;
}
}
};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<int N, class Policies>
// struct container_policy : converter_policy_tag
struct container_policy : conversion_policy<N>
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
// BOOST_STATIC_CONSTANT(int, index = N);
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) static void precall(lua_State*, const index_map&) {}
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) static void postcall(lua_State*, const index_map&) {}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) struct only_accepts_nonconst_pointers {};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<class T, class Direction>
struct apply
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
typedef typename boost::mpl::if_<boost::is_same<lua_to_cpp, Direction>
, container_converter_lua_to_cpp<Policies>
, container_converter_cpp_to_lua<Policies>
>::type type;
};
};
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
}}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
namespace luabind
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif) ![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif) {
template<int N>
detail::policy_cons<detail::container_policy<N, detail::null_type>, detail::null_type>
container(LUABIND_PLACEHOLDER_ARG(N))
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return detail::policy_cons<detail::container_policy<N, detail::null_type>, detail::null_type>();
}
![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
template<int N, class Policies>
detail::policy_cons<detail::container_policy<N, Policies>, detail::null_type>
container(LUABIND_PLACEHOLDER_ARG(N), const Policies&)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif) {
return detail::policy_cons<detail::container_policy<N, Policies>, detail::null_type>();
}
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
#endif // LUABIND_CONTAINER_POLICY_HPP_INCLUDED
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
看一下,眼熟吗,感觉怎样?不过是container_converter_lua_to_cpp对应着default_converter::from而container_converter_cpp_to_lua对应着default_converter::to。 当然,policy除了converter以为,还有关于对象生命周期的控制,具体的可以参加luabind目录下的其他policy。
|