diff --git a/examples/functions_empty_arguments.cpp b/examples/functions_empty_arguments.cpp new file mode 100644 index 00000000..d2178e22 --- /dev/null +++ b/examples/functions_empty_arguments.cpp @@ -0,0 +1,53 @@ +#define SOL_CHECK_ARGUMENTS 1 +#include + +#include "assert.hpp" +#include + +int main(int, char*[]) { + std::cout << "=== functions empty args ===" << std::endl; + + // sol::reference, sol::Stack_reference, + // sol::object (and main_* types) can all be + // used to capture "nil", or "none" when a function + // leaves it off + auto my_defaulting_function = [](sol::object maybe_defaulted) -> int { + // if it's nil, it's "unused" or "inactive" + bool inactive = maybe_defaulted == sol::lua_nil; + if (inactive) { + return 0; + } + if (maybe_defaulted.is()) { + int value = maybe_defaulted.as(); + return value; + } + return 1; + }; + + sol::state lua; + lua.open_libraries(sol::lib::base); + + // copy function in (use std::ref to change this behavior) + lua.set_function("defaulting_function", my_defaulting_function); + + sol::string_view code = R"( + result = defaulting_function(24) + result_nothing = defaulting_function() + result_nil = defaulting_function(nil) + result_string = defaulting_function('meow') + print('defaulting_function(24), returned:', result) + print('defaulting_function(), returned:', result_nothing) + print('defaulting_function(nil), returned:', result_nil) + print('defaulting_function(\'meow\'), returned:', result_string) + assert(result == 24) + assert(result_nothing == 0) + assert(result_nil == 0) + assert(result_string == 1) + )"; + + lua.safe_script(code); + + std::cout << std::endl; + + return 0; +} \ No newline at end of file diff --git a/single/sol/sol.hpp b/single/sol/sol.hpp index 8fadd873..9efd5b1d 100644 --- a/single/sol/sol.hpp +++ b/single/sol/sol.hpp @@ -7899,12 +7899,7 @@ namespace stack { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); - bool success = !lua_isnone(L, index); - if (!success) { - // expected type, actual type - handler(L, index, type::poly, type_of(L, index), ""); - } - return success; + return true; } }; diff --git a/sol/stack_check.hpp b/sol/stack_check.hpp index 6853c0e5..441dbc17 100644 --- a/sol/stack_check.hpp +++ b/sol/stack_check.hpp @@ -239,7 +239,7 @@ namespace stack { template static bool check(lua_State* L, int index, Handler&& handler, record& tracking) { tracking.use(1); - bool success = !lua_isnone(L, index); + bool success = is_lua_reference::value || !lua_isnone(L, index); if (!success) { // expected type, actual type handler(L, index, type::poly, type_of(L, index), ""); diff --git a/sol/stack_check_get.hpp b/sol/stack_check_get.hpp index 87997e1c..19a537db 100644 --- a/sol/stack_check_get.hpp +++ b/sol/stack_check_get.hpp @@ -135,15 +135,16 @@ namespace stack { typedef std::integral_constant V_is_empty; template - static optional get_empty(std::true_type, lua_State* L, int index, Handler&& handler, record& tracking) { + static optional get_empty(std::true_type, lua_State*, int, Handler&&, record&) { return nullopt; } template - static optional get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record& tracking) { + static optional get_empty(std::false_type, lua_State* L, int index, Handler&& handler, record&) { typedef std::variant_alternative_t<0, V> T; // This should never be reached... // please check your code and understand what you did to bring yourself here + // maybe file a bug report, or 5 handler(L, index, type::poly, type_of(L, index), "this variant code should never be reached: if it has, you have done something so terribly wrong"); return nullopt; } diff --git a/tests/test_functions.cpp b/tests/test_functions.cpp index b2c876d7..e23ee0d7 100644 --- a/tests/test_functions.cpp +++ b/tests/test_functions.cpp @@ -1490,6 +1490,54 @@ TEST_CASE("functions/unique_usertype overloading", "make sure overloading can wo }; } +TEST_CASE("functions/lua style default arguments", "allow default arguments using sol::reference and sol::object") { + auto def_f1 = [](sol::object defaulted) -> int { + bool inactive = defaulted == sol::lua_nil; // inactive by default + if (inactive) { + return 20; + } + return 10; + }; + auto def_f2 = [](sol::reference defaulted) -> int { + bool inactive = defaulted == sol::lua_nil; // inactive by default + if (inactive) { + return 20; + } + return 10; + }; + auto def_f3 = [](sol::stack_reference defaulted) -> int { + bool inactive = defaulted == sol::lua_nil; // inactive by default + if (inactive) { + return 20; + } + return 10; + }; + + sol::state lua; + lua.set_function("f1", def_f1); + lua.set_function("f2", def_f2); + lua.set_function("f3", def_f3); + + auto result = lua.safe_script(R"( + v1d, v1nd = f1(), f1(1) + v2d, v2nd = f2(), f2(1) + v3d, v3nd = f3(), f3(1) + )", sol::script_pass_on_error); + REQUIRE(result.valid()); + int v1d = lua["v1d"]; + int v1nd = lua["v1nd"]; + int v2d = lua["v2d"]; + int v2nd = lua["v2nd"]; + int v3d = lua["v3d"]; + int v3nd = lua["v3nd"]; + REQUIRE(20 == v1d); + REQUIRE(20 == v2d); + REQUIRE(20 == v3d); + REQUIRE(10 == v1nd); + REQUIRE(10 == v2nd); + REQUIRE(10 == v3nd); +} + #if !defined(_MSC_VER) || !(defined(_WIN32) && !defined(_WIN64)) TEST_CASE("functions/noexcept", "allow noexcept functions to be serialized properly into Lua using sol2") {