From 92a6fb8c1108a20689698dd9076817f42b36d117 Mon Sep 17 00:00:00 2001 From: ThePhD Date: Thu, 24 Aug 2017 14:39:02 -0400 Subject: [PATCH] update all the examples fix implicitly convertible function pointers from classes using `call_detail`'s `lua_call_wrapper` specificaly add documentation for working with `std::function` --- docs/source/usertypes.rst | 14 ++- examples/any_return.cpp | 2 +- examples/basic.cpp | 2 +- examples/config.cpp | 2 +- examples/containers.cpp | 2 +- examples/containers_as_table.cpp | 2 +- examples/coroutine.cpp | 4 +- examples/customization.cpp | 2 +- examples/dynamic_object.cpp | 2 +- examples/environment_snooping.cpp | 2 +- examples/environments.cpp | 2 +- examples/environments_on_functions.cpp | 2 +- examples/functions.cpp | 2 +- examples/multi_results.cpp | 2 +- examples/namespacing.cpp | 2 +- examples/optional_with_iteration.cpp | 2 +- examples/overloading.cpp | 2 +- examples/pairs.cpp | 94 ++++++++++++++++++++ examples/pairs_with_raw_functions.cpp | 96 +++++++++++++++++++++ examples/protected_functions.cpp | 2 +- examples/require.cpp | 2 +- examples/script_error_handling.cpp | 4 +- examples/self_call.cpp | 2 +- examples/self_from_lua.cpp | 2 +- examples/static_variables.cpp | 2 +- examples/tables.cpp | 2 +- examples/usertype.cpp | 2 +- examples/usertype_advanced.cpp | 2 +- examples/usertype_bitfields.cpp | 2 +- examples/usertype_dynamic_getter_setter.cpp | 2 +- examples/usertype_initializers.cpp | 2 +- examples/usertype_simple.cpp | 2 +- examples/usertype_special_functions.cpp | 2 +- examples/usertype_var.cpp | 2 +- examples/variables.cpp | 2 +- examples/variadic_args.cpp | 2 +- single/sol/sol.hpp | 71 +++++++++++---- sol/call.hpp | 20 ++++- sol/container_traits.hpp | 2 +- sol/filters.hpp | 2 +- sol/function_types.hpp | 2 +- sol/stack_get.hpp | 4 +- sol/stack_push.hpp | 9 +- sol/traits.hpp | 24 +++++- sol/types.hpp | 2 +- sol/wrapper.hpp | 2 +- 46 files changed, 345 insertions(+), 67 deletions(-) create mode 100644 examples/pairs.cpp create mode 100644 examples/pairs_with_raw_functions.cpp diff --git a/docs/source/usertypes.rst b/docs/source/usertypes.rst index 24e53bb4..554ab911 100644 --- a/docs/source/usertypes.rst +++ b/docs/source/usertypes.rst @@ -16,6 +16,9 @@ The examples folder also has a number of really great examples for you to see. T * `Certain operators`_ are detected and bound automatically for usertypes * You can use bitfields but it requires some finesse on your part. We have an example to help you get started `here, that uses a few tricks`_. * All usertypes are runtime extensible in both `Lua`_ and `C++`_ + - If you need dynamic callbacks or runtime overridable functions, have a ``std::function`` member variable and get/set it on the usertype object + - ``std::function`` works as a member variable or in passing as an argument / returning as a value (you can even use it with ``sol::property``) + - You can also create an entirely dynamic object: see the `dynamic_object example`_ for more details * You can use :doc:`filters` to control dependencies and streamline return values, as well as apply custom behavior to a functions return * Please note that the colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods - ``obj:method_name()`` is how you call "member" methods in Lua @@ -33,12 +36,14 @@ The examples folder also has a number of really great examples for you to see. T - Retrieve a plain ``T`` to get a copy - Return types and passing arguments to ``sol::function``-types use perfect forwarding and reference semantics, which means no copies happen unless you specify a value explicitly. See :ref:`this note for details`. * You can set ``index`` and ``new_index`` freely on any usertype you like to override the default "if a key is missing, find it / set it here" functionality of a specific object of a usertype. - - new_index and index will not be called if you try to manipulate the named usertype table directly. sol2's will be called to add that function to the usertype's function/variable lookup table. - - new_index and index will be called if you attempt to call a key that does not exist on an actual userdata object (the C++ object) itself. - - If you made a usertype named ``test``, this means ``t = test()``, with ``t.hi = 54`` will call your function, but ``test.hi = function () print ("hi");`` will instead the key ``hi`` to to that function for all ``test`` types + - ``new_index`` and ``index`` will not be called if you try to manipulate the named usertype table directly. sol2's will be called to add that function to the usertype's function/variable lookup table. + - ``new_index`` and ``index`` will be called if you attempt to call a key that does not exist on an actual userdata object (the C++ object) itself. + - If you made a usertype named ``test``, this means ``t = test()``, with ``t.hi = 54`` will call your function, but ``test.hi = function () print ("hi"); end`` will instead set the key ``hi`` to to lookup that function for all ``test`` types * The first ``sizeof( void* )`` bytes is always a pointer to the typed C++ memory. What comes after is based on what you've pushed into the system according to :doc:`the memory specification for usertypes`. This is compatible with a number of systems other than just sol2, making it easy to interop with select other Lua systems. * Member methods, properties, variables and functions taking ``self&`` arguments modify data directly - - Work on a copy by taking arguments or returning by value. Do not use r-value references: they do not mean anything in Lua code. + - Work on a copy by taking arguments or returning by value. + - Do not use r-value references: they do not mean anything in Lua code. + - Move-only types can only be taken by reference: sol2 cannot know if/when to move a value (except when serializing with perfect forwarding *into* Lua) * The actual metatable associated with the usertype has a long name and is defined to be opaque by the Sol implementation. * The actual metatable inner workings is opaque and defined by the Sol implementation, and there are no internal docs because optimizations on the operations are applied based on heuristics we discover from performance testing the system. @@ -46,3 +51,4 @@ The examples folder also has a number of really great examples for you to see. T .. _Lua: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_advanced.cpp#L81 .. _C++: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_simple.cpp#L51 .. _Certain operators: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_automatic_operators.cpp +.. _dynamic_object example: https://github.com/ThePhD/sol2/blob/develop/examples/dynamic_object.cpp diff --git a/examples/any_return.cpp b/examples/any_return.cpp index f433a0e1..bfaf0c09 100644 --- a/examples/any_return.cpp +++ b/examples/any_return.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/basic.cpp b/examples/basic.cpp index b7174121..db255d74 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/config.cpp b/examples/config.cpp index 9df5f5ff..a751e789 100644 --- a/examples/config.cpp +++ b/examples/config.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/containers.cpp b/examples/containers.cpp index d2f8c282..4314dea8 100644 --- a/examples/containers.cpp +++ b/examples/containers.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/containers_as_table.cpp b/examples/containers_as_table.cpp index 4c50c4d3..d3872403 100644 --- a/examples/containers_as_table.cpp +++ b/examples/containers_as_table.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/coroutine.cpp b/examples/coroutine.cpp index 927f7f1a..3d5d05f3 100644 --- a/examples/coroutine.cpp +++ b/examples/coroutine.cpp @@ -1,5 +1,5 @@ -#define SOL_CHECK_ARGUMENTS -#include "sol.hpp" +#define SOL_CHECK_ARGUMENTS 1 +#include #include #include diff --git a/examples/customization.cpp b/examples/customization.cpp index 189708eb..107e53ed 100644 --- a/examples/customization.cpp +++ b/examples/customization.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/dynamic_object.cpp b/examples/dynamic_object.cpp index 3f438328..8af23da3 100644 --- a/examples/dynamic_object.cpp +++ b/examples/dynamic_object.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/environment_snooping.cpp b/examples/environment_snooping.cpp index cd7da06c..06e1cb82 100644 --- a/examples/environment_snooping.cpp +++ b/examples/environment_snooping.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/environments.cpp b/examples/environments.cpp index afe71453..ef643117 100644 --- a/examples/environments.cpp +++ b/examples/environments.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/environments_on_functions.cpp b/examples/environments_on_functions.cpp index f33f5b4b..063a1d30 100644 --- a/examples/environments_on_functions.cpp +++ b/examples/environments_on_functions.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/functions.cpp b/examples/functions.cpp index 3b6d7781..3ce8fa9d 100644 --- a/examples/functions.cpp +++ b/examples/functions.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/multi_results.cpp b/examples/multi_results.cpp index 241d1cf7..e51b7bb8 100644 --- a/examples/multi_results.cpp +++ b/examples/multi_results.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/namespacing.cpp b/examples/namespacing.cpp index d968df97..9169b20a 100644 --- a/examples/namespacing.cpp +++ b/examples/namespacing.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/optional_with_iteration.cpp b/examples/optional_with_iteration.cpp index 2c6fc335..b04f911f 100644 --- a/examples/optional_with_iteration.cpp +++ b/examples/optional_with_iteration.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/overloading.cpp b/examples/overloading.cpp index 1d068557..6044ebc2 100644 --- a/examples/overloading.cpp +++ b/examples/overloading.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/pairs.cpp b/examples/pairs.cpp new file mode 100644 index 00000000..dc746e24 --- /dev/null +++ b/examples/pairs.cpp @@ -0,0 +1,94 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include +#include + +struct my_thing { + std::map m{ + { "bark", 20 }, + { "woof", 60 }, + { "borf", 30 }, + { "awoo", 5 }, + }; + + my_thing() { + + } +}; + +struct lua_iterator_state { + typedef std::map::iterator it_t; + it_t it; + it_t last; + std::reference_wrapper source; + + lua_iterator_state(my_thing& mt) : it(mt.m.begin()), last(mt.m.end()), source(mt) {} +}; + +std::tuple my_next(sol::user user_it_state, sol::this_state l) { + // this gets called + // to start the first iteration, and every + // iteration there after + + // the state you passed in my_pairs is argument 1 + // the key value is argument 2, but we do not + // care about the key value here + lua_iterator_state& it_state = user_it_state; + my_thing& source = it_state.source; + auto& it = it_state.it; + if (it == it_state.last) { + // return nil to signify that + // there's nothing more to work with. + return std::make_tuple( + sol::object(sol::lua_nil), + sol::object(sol::lua_nil) + ); + } + auto itderef = *it; + // 2 values are returned (pushed onto the stack): + // the key and the value + // the state is left alone + auto r = std::make_tuple(sol::object(l, sol::in_place, it->first), sol::object(l, sol::in_place, it->second)); + // the iterator must be moved forward one before we return + std::advance(it, 1); + return r; +}; + +auto my_pairs(my_thing& mt) { + // pairs expects 3 returns: + // the "next" function on how to advance, + // the "table" itself or some state, + // and an initial key value (can be nil) + + // prepare our state + lua_iterator_state it_state(mt); + // sol::user is a space/time optimization over regular usertypes, + // it's incompatible with regular usertypes and stores the type T directly in lua without any pretty setup + // saves space allocation and a single dereference + return std::make_tuple(&my_next, sol::user(std::move(it_state)), sol::lua_nil); +}; + + + +int main(int argc, char* argv[]) { + std::cout << "===== pairs (advanced) =====" << std::endl; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("my_thing", + sol::meta_function::pairs, my_pairs + ); + + lua.safe_script(R"( +local mt = my_thing.new() +for k, v in pairs(mt) do + print(k, v) +end +)"); + + std::cout << std::endl; + + return 0; +} diff --git a/examples/pairs_with_raw_functions.cpp b/examples/pairs_with_raw_functions.cpp new file mode 100644 index 00000000..d15a8bd9 --- /dev/null +++ b/examples/pairs_with_raw_functions.cpp @@ -0,0 +1,96 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include +#include + +struct my_thing { + std::map m{ + { "bark", 20 }, + { "woof", 60 }, + { "borf", 30 }, + { "awoo", 5 }, + }; + + my_thing() { + + } +}; + +struct lua_iterator_state { + typedef std::map::iterator it_t; + it_t it; + it_t last; + std::reference_wrapper source; + + lua_iterator_state(my_thing& mt) : it(mt.m.begin()), last(mt.m.end()), source(mt) {} +}; + +int my_next(lua_State* L) { + // this gets called + // to start the first iteration, and every + // iteration there after + // the state you passed in pairs is argument 1 + // the key value is argument 2 + // we do not care about the key value here + lua_iterator_state& it_state = sol::stack::get>(L, 1); + my_thing& source = it_state.source; + auto& it = it_state.it; + if (it == it_state.last) { + return sol::stack::push(L, sol::lua_nil); + } + auto itderef = *it; + // 2 values are returned (pushed onto the stack): + // the key and the value + // the state is left alone + int pushed = sol::stack::push(L, itderef.first); + pushed += sol::stack::push_reference(L, itderef.second); + std::advance(it, 1); + return pushed; +}; + +auto my_pairs(my_thing& mt) { + // prepare our state + lua_iterator_state it_state(mt); + return std::make_tuple(&my_next, sol::user(std::move(it_state)), sol::lua_nil); + // sol::user above is a space/time optimization over regular usertypes, + // it's incompatible with regular usertypes and stores the type T directly in lua without any pretty setup + // saves space allocation and a single dereference +}; + +int my_pairs(lua_State* L) { + my_thing& mt = sol::stack::get(L, 1); + lua_iterator_state it_state(mt); + // pairs expects 3 returns: + // the "next" function on how to advance, + // the "table" itself or some state, + // and an initial key value (can be nil) + + // next function controls iteration + int pushed = sol::stack::push(L, my_next); + pushed += sol::stack::push>(L, std::move(it_state)); + pushed += sol::stack::push(L, sol::lua_nil); + return pushed; +}; + +int main(int argc, char* argv[]) { + std::cout << "===== pairs (using raw Lua C functions) (advanced) =====" << std::endl; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + lua.new_usertype("my_thing", + sol::meta_function::pairs, my_pairs + ); + + lua.safe_script(R"( +local mt = my_thing.new() +for k, v in pairs(mt) do + print(k, v) +end +)"); + + std::cout << std::endl; + + return 0; +} diff --git a/examples/protected_functions.cpp b/examples/protected_functions.cpp index 91c61363..fcbb12ed 100644 --- a/examples/protected_functions.cpp +++ b/examples/protected_functions.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/require.cpp b/examples/require.cpp index 3ccc0405..8d5d190f 100644 --- a/examples/require.cpp +++ b/examples/require.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/script_error_handling.cpp b/examples/script_error_handling.cpp index 3c18ba38..66c4e3e1 100644 --- a/examples/script_error_handling.cpp +++ b/examples/script_error_handling.cpp @@ -1,6 +1,6 @@ -#define SOL_CHECK_ARGUMENTS - +#define SOL_CHECK_ARGUMENTS 1 #include + #include int main(int, char**) { diff --git a/examples/self_call.cpp b/examples/self_call.cpp index 5f727c5a..fa243860 100644 --- a/examples/self_call.cpp +++ b/examples/self_call.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/self_from_lua.cpp b/examples/self_from_lua.cpp index f8ec4f5a..ba10738b 100644 --- a/examples/self_from_lua.cpp +++ b/examples/self_from_lua.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/static_variables.cpp b/examples/static_variables.cpp index d27f7d1b..2eedc39d 100644 --- a/examples/static_variables.cpp +++ b/examples/static_variables.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/tables.cpp b/examples/tables.cpp index 4b8d8abe..1247c796 100644 --- a/examples/tables.cpp +++ b/examples/tables.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype.cpp b/examples/usertype.cpp index 5b2e934c..3aea33fb 100644 --- a/examples/usertype.cpp +++ b/examples/usertype.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_advanced.cpp b/examples/usertype_advanced.cpp index 2307016a..9866edea 100644 --- a/examples/usertype_advanced.cpp +++ b/examples/usertype_advanced.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_bitfields.cpp b/examples/usertype_bitfields.cpp index ad8e9628..6572ce63 100644 --- a/examples/usertype_bitfields.cpp +++ b/examples/usertype_bitfields.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_dynamic_getter_setter.cpp b/examples/usertype_dynamic_getter_setter.cpp index c8b10499..e33e271d 100644 --- a/examples/usertype_dynamic_getter_setter.cpp +++ b/examples/usertype_dynamic_getter_setter.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_initializers.cpp b/examples/usertype_initializers.cpp index c0828b07..8aad45eb 100644 --- a/examples/usertype_initializers.cpp +++ b/examples/usertype_initializers.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_simple.cpp b/examples/usertype_simple.cpp index dce8d229..16bfe3bb 100644 --- a/examples/usertype_simple.cpp +++ b/examples/usertype_simple.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_special_functions.cpp b/examples/usertype_special_functions.cpp index 1d6ca599..f68ca56e 100644 --- a/examples/usertype_special_functions.cpp +++ b/examples/usertype_special_functions.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/usertype_var.cpp b/examples/usertype_var.cpp index ec6d1acc..2142c857 100644 --- a/examples/usertype_var.cpp +++ b/examples/usertype_var.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/variables.cpp b/examples/variables.cpp index f8c6f336..c8f5b7fd 100644 --- a/examples/variables.cpp +++ b/examples/variables.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/examples/variadic_args.cpp b/examples/variadic_args.cpp index 2f86f68e..591558a2 100644 --- a/examples/variadic_args.cpp +++ b/examples/variadic_args.cpp @@ -1,4 +1,4 @@ -#define SOL_CHECK_ARGUMENTS +#define SOL_CHECK_ARGUMENTS 1 #include #include diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 201a28f6..6df2ba69 100644 --- a/single/sol/sol.hpp +++ b/single/sol/sol.hpp @@ -20,8 +20,8 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // This file was generated with a script. -// Generated 2017-08-22 14:53:37.052568 UTC -// This header was generated with sol v2.18.1 (revision 7164a8a) +// Generated 2017-08-24 18:37:55.297938 UTC +// This header was generated with sol v2.18.1 (revision a163ae7) // https://github.com/ThePhD/sol2 #ifndef SOL_SINGLE_INCLUDE_HPP @@ -1088,16 +1088,34 @@ namespace sol { namespace meta_detail { - template>::value> + template struct is_callable : std::is_function> {}; template - struct is_callable { + struct is_callable>::value && std::is_destructible>::value>> { using yes = char; using no = struct { char s[2]; }; struct F { void operator()(); }; - struct Derived : T, F { ~Derived() = default; }; + struct Derived : T, F { }; + template struct Check; + + template + static no test(Check*); + + template + static yes test(...); + + static const bool value = sizeof(test(0)) == sizeof(yes); + }; + + template + struct is_callable>::value && !std::is_destructible>::value>> { + using yes = char; + using no = struct { char s[2]; }; + + struct F { void operator()(); }; + struct Derived : T, F { ~Derived() = delete; }; template struct Check; template @@ -3898,7 +3916,7 @@ namespace sol { template struct filter_wrapper { - typedef std::make_integer_sequence indices; + typedef std::index_sequence_for indices; F value; std::tuple filters; @@ -4208,7 +4226,7 @@ namespace sol { U value; user(U x) : value(std::move(x)) {} - operator U* () { return std::addressof(value); } + operator std::remove_reference_t* () { return std::addressof(value); } operator U& () { return value; } operator const U& () const { return value; } }; @@ -7053,9 +7071,9 @@ namespace sol { template struct getter> { - static T& get(lua_State* L, int index, record& tracking) { + static std::add_lvalue_reference_t get(lua_State* L, int index, record& tracking) { tracking.use(1); - return *static_cast(lua_touserdata(L, index)); + return *static_cast*>(lua_touserdata(L, index)); } }; @@ -7726,7 +7744,14 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, + std::is_function>, + std::is_base_of>, + std::is_base_of> + >::value + >> { template static int push(lua_State* L, Args&&... args) { return pusher>{}.push(L, std::forward(args)...); @@ -9136,7 +9161,7 @@ namespace sol { template struct wrapper { - typedef lua_bind_traits> traits_type; + typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; typedef typename traits_type::args_list free_args_list; typedef typename traits_type::returns_list returns_list; @@ -9779,14 +9804,30 @@ namespace sol { template struct agnostic_lua_call_wrapper { + typedef wrapper> wrap; + template - static int call(lua_State* L, Fx&& f, Args&&... args) { - typedef wrapper> wrap; + static int convertible_call(std::true_type, lua_State* L, Fx&& f, Args&&... args) { + typedef typename wrap::traits_type traits_type; + typedef typename traits_type::function_pointer_type fp_t; + fp_t fx = f; + return agnostic_lua_call_wrapper{}.call(L, fx, std::forward(args)...); + } + + template + static int convertible_call(std::false_type, lua_State* L, Fx&& f, Args&&... args) { typedef typename wrap::returns_list returns_list; typedef typename wrap::free_args_list args_list; typedef typename wrap::caller caller; return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); } + + template + static int call(lua_State* L, Fx&& f, Args&&... args) { + typedef typename wrap::traits_type traits_type; + typedef typename traits_type::function_pointer_type fp_t; + return convertible_call(std::conditional_t>::value, std::is_convertible, fp_t>, std::false_type>(), L, std::forward(f), std::forward(args)...); + } }; template @@ -11110,7 +11151,7 @@ namespace sol { template struct pusher, + std::is_function>, meta::neg>, meta::neg>> #ifdef SOL_NOEXCEPT_FUNCTION_TYPE @@ -13573,7 +13614,7 @@ namespace sol { auto& src = get_src(L); stack::push(L, next); stack::push>(L, src, deferred_traits::begin(L, src)); - stack::push(L, 1); + stack::push(L, sol::lua_nil); return 3; } diff --git a/sol/call.hpp b/sol/call.hpp index a2a51b93..c4ace21a 100644 --- a/sol/call.hpp +++ b/sol/call.hpp @@ -230,14 +230,30 @@ namespace sol { template struct agnostic_lua_call_wrapper { + typedef wrapper> wrap; + template - static int call(lua_State* L, Fx&& f, Args&&... args) { - typedef wrapper> wrap; + static int convertible_call(std::true_type, lua_State* L, Fx&& f, Args&&... args) { + typedef typename wrap::traits_type traits_type; + typedef typename traits_type::function_pointer_type fp_t; + fp_t fx = f; + return agnostic_lua_call_wrapper{}.call(L, fx, std::forward(args)...); + } + + template + static int convertible_call(std::false_type, lua_State* L, Fx&& f, Args&&... args) { typedef typename wrap::returns_list returns_list; typedef typename wrap::free_args_list args_list; typedef typename wrap::caller caller; return stack::call_into_lua(returns_list(), args_list(), L, boost + 1, caller(), std::forward(f), std::forward(args)...); } + + template + static int call(lua_State* L, Fx&& f, Args&&... args) { + typedef typename wrap::traits_type traits_type; + typedef typename traits_type::function_pointer_type fp_t; + return convertible_call(std::conditional_t>::value, std::is_convertible, fp_t>, std::false_type>(), L, std::forward(f), std::forward(args)...); + } }; template diff --git a/sol/container_traits.hpp b/sol/container_traits.hpp index ddfbb85b..97d8fdb2 100644 --- a/sol/container_traits.hpp +++ b/sol/container_traits.hpp @@ -960,7 +960,7 @@ namespace sol { auto& src = get_src(L); stack::push(L, next); stack::push>(L, src, deferred_traits::begin(L, src)); - stack::push(L, 1); + stack::push(L, sol::lua_nil); return 3; } diff --git a/sol/filters.hpp b/sol/filters.hpp index 824320f1..c17bb176 100644 --- a/sol/filters.hpp +++ b/sol/filters.hpp @@ -63,7 +63,7 @@ namespace sol { template struct filter_wrapper { - typedef std::make_integer_sequence indices; + typedef std::index_sequence_for indices; F value; std::tuple filters; diff --git a/sol/function_types.hpp b/sol/function_types.hpp index 9930941a..7ce94505 100644 --- a/sol/function_types.hpp +++ b/sol/function_types.hpp @@ -261,7 +261,7 @@ namespace sol { template struct pusher, + std::is_function>, meta::neg>, meta::neg>> #ifdef SOL_NOEXCEPT_FUNCTION_TYPE diff --git a/sol/stack_get.hpp b/sol/stack_get.hpp index e99b0e9b..7ac70f06 100644 --- a/sol/stack_get.hpp +++ b/sol/stack_get.hpp @@ -363,9 +363,9 @@ namespace sol { template struct getter> { - static T& get(lua_State* L, int index, record& tracking) { + static std::add_lvalue_reference_t get(lua_State* L, int index, record& tracking) { tracking.use(1); - return *static_cast(lua_touserdata(L, index)); + return *static_cast*>(lua_touserdata(L, index)); } }; diff --git a/sol/stack_push.hpp b/sol/stack_push.hpp index 6b280f6f..9f6f47c2 100644 --- a/sol/stack_push.hpp +++ b/sol/stack_push.hpp @@ -137,7 +137,14 @@ namespace sol { }; template - struct pusher>, meta::neg>, std::is_base_of>>>>::value>> { + struct pusher>, + std::is_function>, + std::is_base_of>, + std::is_base_of> + >::value + >> { template static int push(lua_State* L, Args&&... args) { return pusher>{}.push(L, std::forward(args)...); diff --git a/sol/traits.hpp b/sol/traits.hpp index b65e8e87..13d35dde 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -252,16 +252,34 @@ namespace sol { namespace meta_detail { - template>::value> + template struct is_callable : std::is_function> {}; template - struct is_callable { + struct is_callable>::value && std::is_destructible>::value>> { using yes = char; using no = struct { char s[2]; }; struct F { void operator()(); }; - struct Derived : T, F { ~Derived() = default; }; + struct Derived : T, F { }; + template struct Check; + + template + static no test(Check*); + + template + static yes test(...); + + static const bool value = sizeof(test(0)) == sizeof(yes); + }; + + template + struct is_callable>::value && !std::is_destructible>::value>> { + using yes = char; + using no = struct { char s[2]; }; + + struct F { void operator()(); }; + struct Derived : T, F { ~Derived() = delete; }; template struct Check; template diff --git a/sol/types.hpp b/sol/types.hpp index 3805e8d9..bf9bcf5d 100644 --- a/sol/types.hpp +++ b/sol/types.hpp @@ -325,7 +325,7 @@ namespace sol { U value; user(U x) : value(std::move(x)) {} - operator U* () { return std::addressof(value); } + operator std::remove_reference_t* () { return std::addressof(value); } operator U& () { return value; } operator const U& () const { return value; } }; diff --git a/sol/wrapper.hpp b/sol/wrapper.hpp index 43ff2a72..c1cc6200 100644 --- a/sol/wrapper.hpp +++ b/sol/wrapper.hpp @@ -28,7 +28,7 @@ namespace sol { template struct wrapper { - typedef lua_bind_traits> traits_type; + typedef lua_bind_traits> traits_type; typedef typename traits_type::args_list args_list; typedef typename traits_type::args_list free_args_list; typedef typename traits_type::returns_list returns_list;