Free functions and lambdas whos first arguments match the userdata type (unqualified)

now are usable as functions for userdata.
allows free functions and lambdas to provide useful operations, like operator+*-/
and other things which may not be implemented as class members.
This commit is contained in:
ThePhD 2014-08-09 04:54:58 -07:00
parent 2e44a6cf42
commit 37c3883eb6
10 changed files with 260 additions and 119 deletions

View File

@ -28,7 +28,7 @@
namespace sol {
struct default_construct {
template <typename T, typename... Args>
template<typename T, typename... Args>
void operator()(T&& obj, Args&&... args) const {
std::allocator<Unqualified<T>> alloc{};
alloc.construct(obj, std::forward<Args>(args)...);

View File

@ -86,7 +86,7 @@ public:
};
namespace stack {
template <typename... Sigs>
template<typename... Sigs>
struct pusher<function_sig_t<Sigs...>> {
template<typename R, typename... Args, typename Fx, typename = typename std::result_of<Fx(Args...)>::type>
@ -208,26 +208,26 @@ struct pusher<function_sig_t<Sigs...>> {
stack::push(L, freefunc, 1);
}
template <typename... Args>
template<typename... Args>
static void push(lua_State* L, Args&&... args) {
set(L, std::forward<Args>(args)...);
}
};
template <typename Signature>
template<typename Signature>
struct pusher<std::function<Signature>> {
static void push(lua_State* L, std::function<Signature> fx) {
pusher<function_t>{}.push(L, std::move(fx));
}
};
template <typename Signature>
template<typename Signature>
struct getter<std::function<Signature>> {
typedef function_traits<Signature> fx_t;
typedef typename fx_t::args_type args_t;
typedef typename tuple_types<typename fx_t::return_type>::type ret_t;
template <typename... FxArgs, typename... Ret>
template<typename... FxArgs, typename... Ret>
static std::function<Signature> get_std_func(types<FxArgs...>, types<Ret...>, lua_State* L, int index = -1) {
typedef typename function_traits<Signature>::return_type return_t;
sol::function f(L, index);
@ -237,7 +237,7 @@ struct getter<std::function<Signature>> {
return std::move(fx);
}
template <typename... FxArgs>
template<typename... FxArgs>
static std::function<Signature> get_std_func(types<FxArgs...>, types<void>, lua_State* L, int index = -1) {
sol::function f(L, index);
auto fx = [ f, L, index ] (FxArgs&&... args) -> void {
@ -246,7 +246,7 @@ struct getter<std::function<Signature>> {
return std::move(fx);
}
template <typename... FxArgs>
template<typename... FxArgs>
static std::function<Signature> get_std_func(types<FxArgs...> t, types<>, lua_State* L, int index = -1) {
return get_std_func(std::move(t), types<void>(), L, index);
}

View File

@ -31,8 +31,12 @@ namespace detail {
struct ref_call_t {};
const auto ref_call = ref_call_t{};
template <typename T, typename Func, typename R, bool is_variable = std::is_member_object_pointer<Func>::value>
template<typename T, typename Func, typename = void>
struct functor {
typedef member_traits<Func> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::return_type return_type;
T* item;
Func invocation;
@ -40,46 +44,75 @@ struct functor {
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
template<typename... Args>
R operator()(Args&&... args) {
T& member = *item;
return (member.*invocation)(std::forward<Args>(args)...);
}
};
template <typename T, typename Func>
struct functor<T, Func, void, false> {
T* item;
Func invocation;
template<typename... FxArgs>
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
template<typename... Args>
void operator()(Args&&... args) {
void call(types<void>, Args&&... args) {
T& member = *item;
(member.*invocation)(std::forward<Args>(args)...);
}
template<typename Ret, typename... Args>
Ret call(types<Ret>, Args&&... args) {
T& member = *item;
return (member.*invocation)(std::forward<Args>(args)...);
}
template<typename... Args>
auto operator()(Args&&... args) -> decltype(this->call(types<return_type>{}, std::forward<Args>(args)...)) {
return this->call(types<return_type>{}, std::forward<Args>(args)...);
}
};
template <typename T, typename Func, typename R>
struct functor<T, Func, R, true> {
template<typename T, typename Func>
struct functor<T, Func, typename std::enable_if<std::is_member_object_pointer<Func>::value>::type> {
typedef member_traits<Func> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::return_type return_type;
T* item;
Func invocation;
template<typename... FxArgs>
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
template<typename Arg, typename... Args>
void operator()(Arg&& arg, Args&&...) {
template<typename Arg>
void operator()(Arg&& arg) {
T& member = *item;
(member.*invocation) = std::forward<Arg>(arg);
}
R operator()() {
return_type operator()() {
T& member = *item;
return (member.*invocation);
}
};
template<typename T, typename Func>
struct functor<T, Func, typename std::enable_if<std::is_function<Func>::value || std::is_class<Func>::value>::type> {
typedef member_traits<Func> traits_type;
typedef remove_one_type<typename traits_type::args_type> args_type;
typedef typename traits_type::return_type return_type;
typedef typename std::conditional<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, typename std::add_pointer<Func>::type>::type function_type;
T* item;
function_type invocation;
template<typename... FxArgs>
functor(FxArgs&&... fxargs): item(nullptr), invocation(std::forward<FxArgs>(fxargs)...) {}
template<typename... Args>
void call(types<void>, Args&&... args) {
T& member = *item;
invocation(member, std::forward<Args>(args)...);
}
template<typename Ret, typename... Args>
Ret call(types<Ret>, Args&&... args) {
T& member = *item;
return invocation(member, std::forward<Args>(args)...);
}
template<typename... Args>
auto operator()(Args&&... args) -> decltype(this->call(types<return_type>{}, std::forward<Args>(args)...)) {
return this->call(types<return_type>{}, std::forward<Args>(args)...);
}
};
} // detail
@ -340,11 +373,12 @@ template<typename Function, typename Tp>
struct userdata_function_core : public base_function {
typedef typename std::remove_pointer<Tp>::type T;
typedef typename std::remove_pointer<typename std::decay<Function>::type>::type function_type;
typedef member_traits<Function> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::return_type return_type;
typedef detail::functor<T, function_type> fx_t;
typedef typename fx_t::traits_type traits_type;
typedef typename fx_t::args_type args_type;
typedef typename fx_t::return_type return_type;
detail::functor<T, function_type, return_type> fx;
fx_t fx;
template<typename... FxArgs>
userdata_function_core(FxArgs&&... fxargs): fx(std::forward<FxArgs>(fxargs)...) {}
@ -398,14 +432,14 @@ template<typename Function, typename Tp>
struct userdata_function : public userdata_function_core<Function, Tp> {
typedef userdata_function_core<Function, Tp> base_t;
typedef typename std::remove_pointer<Tp>::type T;
typedef member_traits<Function> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::return_type return_type;
typedef typename base_t::traits_type traits_type;
typedef typename base_t::args_type args_type;
typedef typename base_t::return_type return_type;
template<typename... FxArgs>
userdata_function(FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...) {}
template <typename Tx>
template<typename Tx>
int fx_call(lua_State* L) {
this->fx.item = detail::get_ptr(stack::get<Tx>(L, 1));
if (this->fx.item == nullptr)
@ -426,14 +460,14 @@ template<typename Function, typename Tp>
struct userdata_variable_function : public userdata_function_core<Function, Tp> {
typedef userdata_function_core<Function, Tp> base_t;
typedef typename std::remove_pointer<Tp>::type T;
typedef member_traits<Function> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::return_type return_type;
typedef typename base_t::traits_type traits_type;
typedef typename base_t::args_type args_type;
typedef typename base_t::return_type return_type;
template<typename... FxArgs>
userdata_variable_function(FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...) {}
template <typename Tx>
template<typename Tx>
int fx_call (lua_State* L) {
this->fx.item = detail::get_ptr(stack::get<Tx>(L, 1));
if (this->fx.item == nullptr)
@ -463,9 +497,9 @@ template<typename Function, typename Tp>
struct userdata_indexing_function : public userdata_function_core<Function, Tp> {
typedef userdata_function_core<Function, Tp> base_t;
typedef typename std::remove_pointer<Tp>::type T;
typedef member_traits<Function> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::return_type return_type;
typedef typename base_t::traits_type traits_type;
typedef typename base_t::args_type args_type;
typedef typename base_t::return_type return_type;
std::string name;
std::unordered_map<std::string, std::pair<std::unique_ptr<base_function>, bool>> functions;
@ -473,7 +507,7 @@ struct userdata_indexing_function : public userdata_function_core<Function, Tp>
template<typename... FxArgs>
userdata_indexing_function(std::string name, FxArgs&&... fxargs): base_t(std::forward<FxArgs>(fxargs)...), name(std::move(name)) {}
template <typename Tx>
template<typename Tx>
int fx_call (lua_State* L) {
std::string accessor = stack::get<std::string>(L, 1 - lua_gettop(L));
auto function = functions.find(accessor);

View File

@ -49,7 +49,7 @@ inline T* get_ptr(T* val) {
return val;
}
template <typename Decorated>
template<typename Decorated>
struct return_forward {
typedef Unqualified<Decorated> T;
@ -83,12 +83,12 @@ inline void push_userdata(lua_State* L, Key&& metatablekey, Args&&... args) {
lua_setmetatable(L, -2);
}
} // detail
template <typename T, typename X = void>
template<typename T, typename X = void>
struct getter;
template <typename T, typename X = void>
template<typename T, typename X = void>
struct pusher;
template <typename T, typename>
template<typename T, typename>
struct getter {
template<typename U = T, EnableIf<std::is_floating_point<U>> = 0>
static U get(lua_State* L, int index = -1) {
@ -118,7 +118,7 @@ struct getter {
}
};
template <typename T>
template<typename T>
struct getter<T*> {
static T* get(lua_State* L, int index = -1) {
void* udata = lua_touserdata(L, index);
@ -127,21 +127,21 @@ struct getter<T*> {
}
};
template <>
template<>
struct getter<type> {
static type get(lua_State *L, int index){
return static_cast<type>(lua_type(L, index));
}
};
template <>
template<>
struct getter<bool> {
static bool get(lua_State* L, int index) {
return lua_toboolean(L, index) != 0;
}
};
template <>
template<>
struct getter<std::string> {
static std::string get(lua_State* L, int index = -1) {
std::string::size_type len;
@ -150,14 +150,14 @@ struct getter<std::string> {
}
};
template <>
template<>
struct getter<const char*> {
static const char* get(lua_State* L, int index = -1) {
return lua_tostring(L, index);
}
};
template <>
template<>
struct getter<nil_t> {
static nil_t get(lua_State* L, int index = -1) {
if (lua_isnil(L, index) == 0)
@ -166,28 +166,28 @@ struct getter<nil_t> {
}
};
template <>
template<>
struct getter<userdata_t> {
static userdata_t get(lua_State* L, int index = -1) {
return{ lua_touserdata(L, index) };
}
};
template <>
template<>
struct getter<lightuserdata_t> {
static lightuserdata_t get(lua_State* L, int index = 1) {
return{ lua_touserdata(L, index) };
}
};
template <>
template<>
struct getter<upvalue_t> {
static upvalue_t get(lua_State* L, int index = 1) {
return{ lua_touserdata(L, lua_upvalueindex(index)) };
}
};
template <>
template<>
struct getter<void*> {
static void* get(lua_State* L, int index = 1) {
return lua_touserdata(L, index);
@ -302,7 +302,7 @@ struct pusher<lightuserdata_t> {
template<>
struct pusher<userdata_t> {
template <typename T, typename U = Unqualified<T>>
template<typename T, typename U = Unqualified<T>>
static void push(lua_State* L, T&& data) {
U* userdata = static_cast<U*>(lua_newuserdata(L, sizeof(U)));
new(userdata)U(std::forward<T>(data));
@ -484,7 +484,7 @@ inline call_syntax get_call_syntax(lua_State* L, const std::string& meta) {
return call_syntax::dot;
}
template <typename T>
template<typename T>
struct get_return {
typedef decltype(get<T>(nullptr)) type;
};

View File

@ -90,9 +90,11 @@ public:
template<typename Key, typename T>
table& set_userdata(Key&& key, userdata<T>& user) {
std::string ukey(std::forward<Key>(key));
push();
stack::push(state(), std::forward<Key>(key));
stack::push(state(), user);
lua_setglobal(state(), ukey.c_str());
lua_settable(state(), -3);
lua_pop(state(), 1);
return *this;
}

View File

@ -27,7 +27,7 @@
#include <functional>
namespace sol {
template <typename T>
template<typename T>
struct identity { typedef T type; };
template<typename... Args>
@ -36,27 +36,27 @@ struct is_tuple : std::false_type{ };
template<typename... Args>
struct is_tuple<std::tuple<Args...>> : std::true_type{ };
template <typename T>
template<typename T>
struct unwrap {
typedef T type;
};
template <typename T>
template<typename T>
struct unwrap<std::reference_wrapper<T>> {
typedef typename std::add_lvalue_reference<T>::type type;
};
template <typename T>
template<typename T>
struct remove_member_pointer;
template <typename R, typename T>
template<typename R, typename T>
struct remove_member_pointer<R T::*> {
typedef R type;
};
template <typename T, template <typename...> class Templ>
template<typename T, template<typename...> class Templ>
struct is_specialization_of : std::false_type { };
template <typename... T, template <typename...> class Templ>
template<typename... T, template<typename...> class Templ>
struct is_specialization_of<Templ<T...>, Templ> : std::true_type { };
template<class T, class...>
@ -104,7 +104,7 @@ using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::t
template<typename T>
using Decay = typename std::decay<T>::type;
template <typename T>
template<typename T>
using Unwrap = typename unwrap<T>::type;
template<typename... Args>
@ -160,26 +160,23 @@ struct check_deducible_signature {
template<class F>
struct has_deducible_signature : detail::check_deducible_signature<F>::type { };
template <typename T>
template<typename T>
using has_deducible_signature_t = typename has_deducible_signature<T>::type;
template<typename T>
struct Function : Bool<detail::is_function_impl<T>::value> {};
template<typename TFuncSignature>
struct function_traits;
namespace detail {
template<typename Signature, bool b = std::is_class<Signature>::value>
struct fx_traits;
template <typename TFuncSignature>
using function_args_t = typename function_traits<TFuncSignature>::args_type;
template<typename Signature>
struct fx_traits<Signature, true> : fx_traits<decltype(Signature::operator()), false> {
template <typename TFuncSignature>
using function_signature_t = typename function_traits<TFuncSignature>::signature_type;
template <typename TFuncSignature>
using function_return_t = typename function_traits<TFuncSignature>::return_type;
};
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...)> {
struct fx_traits<R(T::*)(Args...), false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = true;
typedef std::tuple<Args...> arg_tuple_type;
@ -194,7 +191,7 @@ struct function_traits<R(T::*)(Args...)> {
};
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
struct fx_traits<R(T::*)(Args...) const, false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = true;
typedef std::tuple<Args...> arg_tuple_type;
@ -209,7 +206,7 @@ struct function_traits<R(T::*)(Args...) const> {
};
template<typename R, typename... Args>
struct function_traits<R(Args...)> {
struct fx_traits<R(Args...), false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = false;
typedef std::tuple<Args...> arg_tuple_type;
@ -224,7 +221,7 @@ struct function_traits<R(Args...)> {
};
template<typename R, typename... Args>
struct function_traits<R(*)(Args...)> {
struct fx_traits<R(*)(Args...), false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = false;
typedef std::tuple<Args...> arg_tuple_type;
@ -238,13 +235,27 @@ struct function_traits<R(*)(Args...)> {
using arg = typename std::tuple_element<i, arg_tuple_type>::type;
};
} // detail
template<typename Signature>
struct function_traits : detail::fx_traits<Signature> {};
template<typename Signature>
using function_args_t = typename function_traits<Signature>::args_type;
template<typename Signature>
using function_signature_t = typename function_traits<Signature>::signature_type;
template<typename Signature>
using function_return_t = typename function_traits<Signature>::return_type;
namespace detail {
template <typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
struct member_traits : function_traits<Signature> {
};
template <typename Signature>
template<typename Signature>
struct member_traits<Signature, true> {
typedef typename remove_member_pointer<Signature>::type Arg;
typedef typename remove_member_pointer<Signature>::type R;
@ -262,7 +273,7 @@ struct member_traits<Signature, true> {
};
} // detail
template <typename Signature>
template<typename Signature>
struct member_traits : detail::member_traits<Signature> {
};
@ -294,12 +305,12 @@ struct has_key_value_pair_impl {
template<typename T>
struct has_key_value_pair : decltype(has_key_value_pair_impl::test<T>(0)) {};
template <typename T>
template<typename T>
auto unwrapper(T&& item) -> decltype(std::forward<T>(item)) {
return std::forward<T>(item);
}
template <typename Arg>
template<typename Arg>
Unwrap<Arg> unwrapper(std::reference_wrapper<Arg> arg) {
return arg.get();
}

View File

@ -58,15 +58,26 @@ struct build_reverse_indices<0, Ns...> : indices<Ns...> {};
template<typename... Args>
struct types : build_indices<sizeof...(Args)> { typedef types type; };
namespace detail {
template<class Acc, class... Args>
struct reversed_ : Acc{};
template<typename... RArgs, typename Arg, typename... Args>
struct reversed_<types<RArgs...>, Arg, Args...> : reversed_<types<Arg, RArgs...>, Args...>{};
template<typename Arg>
struct chop_one : types<> {};
template<typename Arg0, typename Arg1, typename... Args>
struct chop_one<types<Arg0, Arg1, Args...>> : types<Arg1, Args...> {};
template<typename Arg, typename... Args>
struct chop_one<types<Arg, Args...>> : types<Args...> {};
} // detail
template<typename... Args>
struct reversed : reversed_<types<>, Args...>{};
struct reversed : detail::reversed_<types<>, Args...>{};
template<typename... Args>
struct tuple_types : types<Args...> {};
@ -74,6 +85,9 @@ struct tuple_types : types<Args...> {};
template<typename... Args>
struct tuple_types<std::tuple<Args...>> : types<Args...> {};
template<typename Arg>
struct remove_one_type : detail::chop_one<Arg> {};
template<typename... Tn>
struct constructors {};

View File

@ -24,7 +24,7 @@
#include <lua.hpp>
#include <string>
#include <type_traits>
#include "traits.hpp"
namespace sol {
struct nil_t {};
@ -32,7 +32,7 @@ const nil_t nil {};
struct void_type {};
const void_type Void {};
template <typename... T>
template<typename... T>
struct function_sig_t {};
using function_t = function_sig_t<>;

View File

@ -65,7 +65,6 @@ const std::array<std::string, 19> meta_function_names = {{
"__gc",
}};
/* Too easy?
enum class meta_function {
index,
new_index,
@ -86,7 +85,7 @@ enum class meta_function {
equal_to,
less_than,
less_than_or_equal_to,
};*/
};
template<typename T>
class userdata {
@ -212,19 +211,56 @@ private:
}
}
template<std::size_t N, typename TBase, typename Ret>
bool build_function(std::true_type, function_map_t*&, function_map_t*&, std::string funcname, Ret TBase::* func) {
static_assert(std::is_base_of<TBase, T>::value, "Any registered function must be part of the class");
template<std::size_t N, typename Base, typename Ret>
bool build_function(std::true_type, function_map_t*&, function_map_t*&, std::string funcname, Ret Base::* func) {
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
typedef typename std::decay<decltype(func)>::type function_type;
indexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_variable_function<function_type, T>>(func), false));
newindexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_variable_function<function_type, T>>(func), false));
return false;
}
template<std::size_t N, typename TBase, typename Ret>
bool build_function(std::false_type, function_map_t*& index, function_map_t*& newindex, std::string funcname, Ret TBase::* func) {
static_assert(std::is_base_of<TBase, T>::value, "Any registered function must be part of the class");
template<typename Arg, typename... Args, typename Ret>
std::unique_ptr<base_function> make_function(const std::string&, Ret(*func)(Arg, Args...)) {
typedef Unqualified<Arg> Argu;
static_assert(std::is_base_of<Argu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
typedef typename std::decay<decltype(func)>::type function_type;
return detail::make_unique<userdata_function<function_type, T>>(func);
}
template<typename Base, typename Ret>
std::unique_ptr<base_function> make_variable_function(std::true_type, const std::string&, Ret Base::* func) {
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
typedef typename std::decay<decltype(func)>::type function_type;
return detail::make_unique<userdata_variable_function<function_type, T>>(func);
}
template<typename Base, typename Ret>
std::unique_ptr<base_function> make_variable_function(std::false_type, const std::string&, Ret Base::* func) {
static_assert(std::is_base_of<Base, T>::value, "Any registered function must be part of the class");
typedef typename std::decay<decltype(func)>::type function_type;
return detail::make_unique<userdata_function<function_type, T>>(func);
}
template<typename Base, typename Ret>
std::unique_ptr<base_function> make_function(const std::string& name, Ret Base::* func) {
typedef typename std::decay<decltype(func)>::type function_type;
return make_variable_function(std::is_member_object_pointer<function_type>(), name, func);
}
template<typename Fx>
std::unique_ptr<base_function> make_function(const std::string&, Fx&& func) {
typedef Unqualified<Fx> Fxu;
typedef typename std::tuple_element<0, typename function_traits<Fxu>::arg_tuple_type>::type TArg;
typedef Unqualified<TArg> TArgu;
static_assert(std::is_base_of<TArgu, T>::value, "Any non-member-function must have a first argument which is covariant with the desired userdata type.");
typedef typename std::decay<decltype(func)>::type function_type;
return detail::make_unique<userdata_function<function_type, T>>(func);
}
template<std::size_t N, typename Fx>
bool build_function(std::false_type, function_map_t*& index, function_map_t*& newindex, std::string funcname, Fx&& func) {
typedef typename std::decay<Fx>::type function_type;
auto metamethod = std::find(meta_function_names.begin(), meta_function_names.end(), funcname);
if (metamethod != meta_function_names.end()) {
functionnames.push_back(std::move(funcname));
@ -246,23 +282,22 @@ private:
ptr = std::move(idxptr);
}
else {
ptr = detail::make_unique<userdata_function<function_type, T>>(func);
ptr = make_function(funcname, std::forward<Fx>(func));
}
metafunctions.emplace_back(std::move(ptr));
metafunctiontable.push_back( { name.c_str(), &base_function::userdata<N>::call } );
ptrmetafunctiontable.push_back( { name.c_str(), &base_function::userdata<N>::ref_call } );
return true;
}
indexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_function<function_type, T>>(func), true ));
newindexmetafunctions.emplace(funcname, std::make_pair(detail::make_unique<userdata_function<function_type, T>>(func), true));
indexmetafunctions.emplace(funcname, std::make_pair(make_function(funcname, std::forward<Fx>(func)), true));
return false;
}
template<std::size_t N, typename TBase, typename Ret, typename... Args>
void build_function_tables(function_map_t*& index, function_map_t*& newindex, std::string funcname, Ret TBase::* func, Args&&... args) {
typedef typename std::is_member_object_pointer<decltype(func)>::type is_variable;
template<std::size_t N, typename Fx, typename... Args>
void build_function_tables(function_map_t*& index, function_map_t*& newindex, std::string funcname, Fx&& func, Args&&... args) {
typedef typename std::is_member_object_pointer<Unqualified<Fx>>::type is_variable;
static const std::size_t V = static_cast<std::size_t>( !is_variable::value );
if (build_function<N>(is_variable(), index, newindex, std::move(funcname), std::move(func))) {
if (build_function<N>(is_variable(), index, newindex, std::move(funcname), std::forward<Fx>(func))) {
build_function_tables<N + V>(index, newindex, std::forward<Args>(args)...);
}
else {
@ -270,13 +305,12 @@ private:
}
}
/* Apparently there needs to be magic
template<std::size_t N, typename TBase, typename Ret, typename... Args>
void build_function_tables(function_map_t*& index, function_map_t*& newindex, meta_function metafunc, Ret TBase::* func, Args&&... args) {
template<std::size_t N, typename Base, typename Ret, typename... Args>
void build_function_tables(function_map_t*& index, function_map_t*& newindex, meta_function metafunc, Ret Base::* func, Args&&... args) {
std::size_t idx = static_cast<std::size_t>(metafunc);
const std::string& funcname = meta_function_names[idx];
build_function_tables<N>(index, newindex, funcname, std::move(func), std::forward<Args>(args)...);
}*/
}
public:
template<typename... Args>
@ -331,7 +365,7 @@ public:
}
private:
template <typename Meta, typename MetaFuncs, typename MetaFuncTable>
template<typename Meta, typename MetaFuncs, typename MetaFuncTable>
static void push_metatable(lua_State* L, Meta&& metakey, MetaFuncs&& metafuncs, MetaFuncTable&& metafunctable) {
luaL_newmetatable(L, std::addressof(metakey[0]));
if (metafunctable.size() > 1) {
@ -355,7 +389,7 @@ private:
lua_setglobal(L, std::addressof(userdata_traits<T>::gctable[0]));
}
template <bool release = false, typename TCont>
template<bool release = false, typename TCont>
static int push_upvalues (lua_State* L, TCont&& cont) {
int n = 0;
for (auto& c : cont) {
@ -370,7 +404,7 @@ private:
};
namespace stack {
template <typename T>
template<typename T>
struct pusher<userdata<T>> {
static void push (lua_State* L, userdata<T>& user) {
user.push(L);

View File

@ -160,6 +160,31 @@ struct Vec {
}
};
struct giver {
int a = 0;
giver () {
}
void gief () {
a = 1;
}
static void stuff () {
}
static void gief_stuff (giver& t, int a) {
t.a = a;
}
~giver () {
}
};
TEST_CASE("simple/set_global", "Check if the set_global works properly.") {
sol::state lua;
@ -809,3 +834,24 @@ TEST_CASE("userdata/member-variables", "allow table-like accessors to behave as
"assert(x == 3)\n"
));
}
TEST_CASE("userdata/nonmember functions implement functionality", "let users set non-member functions that take unqualified T as first parameter to userdata") {
sol::state lua;
lua.open_libraries( sol::lib::base );
lua.new_userdata<giver>( "giver",
"gief_stuff", giver::gief_stuff,
"gief", &giver::gief,
"__tostring", [](const giver& t) {
return std::to_string(t.a) + ": giving value";
}
).get<sol::table>( "giver" )
.set_function( "stuff", giver::stuff );
REQUIRE_NOTHROW(lua.script("giver.stuff()"));
REQUIRE_NOTHROW(lua.script("t = giver.new()\n"
"print(tostring(t))\n"
"t:gief()\n"
"t:gief_stuff(20)\n"));
REQUIRE((lua.get<giver>("t").a == 20));
}