diff --git a/sol/function.hpp b/sol/function.hpp index 4a2fd911..ea972bb4 100644 --- a/sol/function.hpp +++ b/sol/function.hpp @@ -40,12 +40,12 @@ private: int returncount; template - T get(types, indices) const { + stack::get_return get(types, indices) const { return stack::get(L, index); } template - std::tuple get(types, indices) const { + stack::get_return get(types, indices) const { auto r = std::make_tuple(stack::get(L, index + I)...); return r; } @@ -60,12 +60,21 @@ public: function_result(function_result&&) = default; function_result& operator=(function_result&&) = default; - template - operator T () const { - auto tr = tuple_types(); + template + T get() const { + tuple_types> tr; return get(tr, tr); } + operator const char* () const { + return get(); + } + + template, const char*>>, Not, char>>, Not, std::string>>, Not, std::initializer_list>>> = 0> + operator T () const { + return get(); + } + ~function_result() { lua_pop(L, returncount); } @@ -122,12 +131,14 @@ public: } template - ReturnType operator()(types, Args&&... args) const { + auto operator()(types, Args&&... args) const + -> decltype(call(std::forward(args)...)) { return call(std::forward(args)...); } template - auto call(Args&&... args) const -> decltype(invoke(types(), types(), 0)) { + auto call(Args&&... args) const + -> decltype(invoke(types(), types(), 0)) { push(); int pushcount = stack::push_args(state(), std::forward(args)...); auto tr = types(); diff --git a/sol/proxy.hpp b/sol/proxy.hpp index 22667511..a314a017 100644 --- a/sol/proxy.hpp +++ b/sol/proxy.hpp @@ -52,7 +52,7 @@ public: template proxy& set_function(Args&&... args) { tbl.set_function(key, std::forward(args)...); - return *this; + return *this; } template>> = 0> @@ -65,50 +65,24 @@ public: tbl.set(key, std::forward(other)); } - operator nil_t() const { - return get(); + operator const char* () const { + return get(); } - operator object() const { - return get(); - } - - operator function() const { - return get(); - } - - operator Unqualified() const { - return get>(); - } - - operator std::string() const { - return get(); - } - - template - operator bool() const { - return get(); - } - - template - operator double() const { - return get(); - } - - template - operator float() const { - return get(); - } - - template - operator int() const { - return get(); + template, const char*>>, Not, char>>, Not, std::string>>, Not, std::initializer_list>>> = 0> + operator T () const { + return get(); } template - typename return_type::type call(Args&&... args) { + stack::get_return_or call(Args&&... args) { return tbl.template get(key)(types(), std::forward(args)...); } + + template + function_result operator()(Args&&... args) { + return tbl.template get(key)(std::forward(args)...); + } }; template diff --git a/sol/stack.hpp b/sol/stack.hpp index c03cfea6..d0321962 100644 --- a/sol/stack.hpp +++ b/sol/stack.hpp @@ -141,6 +141,12 @@ bool check(lua_State* L, int index) { return check(L, index, handler); } +template +using get_return = ReturnType( nullptr, 0 ))...>; + +template +using get_return_or = ReturnTypeOr( nullptr, 0 ))...>; + namespace detail { const bool default_check_arguments = #ifdef SOL_CHECK_ARGUMENTS @@ -258,7 +264,7 @@ struct getter { type t = type_of(L, index); if (t == type::nil) return nullptr; - return getter{}.get(L, index); + return std::addressof(getter{}.get(L, index)); } }; diff --git a/sol/table.hpp b/sol/table.hpp index 366c1132..a35a1cb5 100644 --- a/sol/table.hpp +++ b/sol/table.hpp @@ -30,24 +30,23 @@ namespace sol { class table : public reference { friend class state; - template - auto single_get(U&& key) const -> decltype(stack::get(nullptr, 0)) { + template + stack::get_return single_get(Key&& key) const { push(); - stack::push(state(), std::forward(key)); + stack::push(state(), std::forward(key)); lua_gettable(state(), -2); - type_assert(state(), -1, type_of()); - auto&& result = stack::pop(state()); - lua_pop(state(), 1); + stack::get_return result = stack::pop(state()); + pop(); return result; } template - auto tuple_get(types, indices, Keys&& keys) const -> decltype(std::make_tuple(single_get(std::get(keys))...)) { - return std::make_tuple(single_get(std::get(keys))...); + stack::get_return tuple_get(types, indices, Keys&& keys) const { + return stack::get_return(single_get(std::get(keys))...); } - template - auto tuple_get(types, indices, Keys&& keys) const -> decltype(single_get(std::get(keys))) { + template + stack::get_return tuple_get(types, indices, Keys&& keys) const { return single_get(std::get(keys)); } @@ -58,9 +57,8 @@ public: } template - auto get(Keys&&... keys) const -> decltype(tuple_get(types(), types(), std::tie(std::forward(keys)...))) { - types tr; - return tuple_get(tr, tr, std::tie(std::forward(keys)...)); + stack::get_return get( Keys&&... keys ) const { + return tuple_get(types(), build_indices(), std::tie(keys...)); } template @@ -116,16 +114,16 @@ public: size_t result = lua_rawlen(state(), -1); pop(); return result; - } - - template - proxy operator[](T&& key) { - return proxy(*this, std::forward(key)); - } - - template - proxy operator[](T&& key) const { - return proxy(*this, std::forward(key)); + } + + template + proxy operator[]( T&& key ) { + return proxy( *this, std::forward( key ) ); + } + + template + proxy operator[]( T&& key ) const { + return proxy( *this, std::forward( key ) ); } void pop(int n = 1) const noexcept { diff --git a/sol/traits.hpp b/sol/traits.hpp index 2e9653a8..22ebcc14 100644 --- a/sol/traits.hpp +++ b/sol/traits.hpp @@ -122,8 +122,11 @@ struct return_type<> { typedef void type; }; +template +using ReturnTypeOr = typename std::conditional<(sizeof...(Tn) < 1), Empty, typename return_type::type>::type; + template -using ReturnType = typename return_type::type; +using ReturnType = ReturnTypeOr; namespace detail { diff --git a/tests.cpp b/tests.cpp index 83be07f6..2b8f8648 100644 --- a/tests.cpp +++ b/tests.cpp @@ -488,6 +488,33 @@ TEST_CASE("functions/return_order_and_multi_get", "Check if return order is in t REQUIRE(tluaget == triple); } +TEST_CASE("functions/deducing_return_order_and_multi_get", "Check if return order is in the same reading order specified in Lua, with regular deducing calls") { + const static std::tuple triple = std::make_tuple(10, 11, 12); + sol::state lua; + lua.set_function( "f_string", []() { return "this is a string!"; } ); + sol::function f_string = lua[ "f_string" ]; + + // Make sure there are no overload collisions / compiler errors for automatic string conversions + std::string f_string_result = f_string(); + REQUIRE(f_string_result == "this is a string!"); + f_string_result = f_string(); + REQUIRE(f_string_result == "this is a string!"); + + lua.set_function("f", [] { + return std::make_tuple(10, 11, 12); + }); + lua.script("function g() return 10, 11, 12 end\nx,y,z = g()"); + std::tuple tcpp = lua.get("f")(); + std::tuple tlua = lua.get("g")(); + std::tuple tluaget = lua.get("x", "y", "z"); + std::cout << "cpp: " << std::get<0>(tcpp) << ',' << std::get<1>(tcpp) << ',' << std::get<2>(tcpp) << std::endl; + std::cout << "lua: " << std::get<0>(tlua) << ',' << std::get<1>(tlua) << ',' << std::get<2>(tlua) << std::endl; + std::cout << "lua xyz: " << lua.get("x") << ',' << lua.get("y") << ',' << lua.get("z") << std::endl; + REQUIRE(tcpp == triple); + REQUIRE(tlua == triple); + REQUIRE(tluaget == triple); +} + TEST_CASE("functions/sol::function to std::function", "check if conversion to std::function works properly and calls with correct arguments") { sol::state lua; lua.open_libraries(sol::lib::base);