diff --git a/examples/optional_with_iteration.cpp b/examples/optional_with_iteration.cpp new file mode 100644 index 00000000..4b4e28a5 --- /dev/null +++ b/examples/optional_with_iteration.cpp @@ -0,0 +1,96 @@ +#define SOL_CHECK_ARGUMENTS 1 + +#include +#include +#include +#include + +int main(int argc, char** argv) { + std::cout << "=== optional and iteration example ===" << std::endl; + + struct thing { + int a = 20; + + thing() = default; + thing(int a) : a(a) {} + }; + + struct super_thing : thing { + int b = 40; + }; + + struct unrelated { + + }; + + sol::state lua; + + // Comment out the new_usertype call + // to prevent derived class "super_thing" + // from being picked up and cast to its base + // class + lua.new_usertype("super_thing", + sol::base_classes, sol::bases() + ); + + // Make a few things + lua["t1"] = thing{}; + lua["t2"] = super_thing{}; + lua["t3"] = unrelated{}; + // And a table + lua["container"] = lua.create_table_with( + 0, thing{50}, + 1, unrelated{}, + 4, super_thing{} + ); + + + std::vector> things; + // Our recursive function + // We use some lambda techniques and pass the function itself itself so we can recurse, + // but a regular function would work too! + auto fx = [&lua, &things](auto& f, auto& tbl) -> void { + // You can iterate through a table: it has + // begin() and end() + // like standard containers + for (auto key_value_pair : tbl) { + // Note that iterators are extremely frail + // and should not be used outside of + // well-constructed for loops + // that use pre-increment ++, + // or C++ ranged-for loops + const sol::object& key = key_value_pair.first; + const sol::object& value = key_value_pair.second; + sol::type t = value.get_type(); + switch (t) { + case sol::type::table: + f(f, value.as()); + break; + case sol::type::userdata: { + // This allows us to check if a userdata is + // a specific class type + sol::optional maybe_thing = value.as>(); + if (maybe_thing) { + thing& the_thing = maybe_thing.value(); + if (key.is()) { + std::cout << "key " << key.as() << " is a thing -- "; + } + else if (key.is()) { + std::cout << "key " << key.as() << " is a thing -- "; + } + std::cout << "thing.a ==" << the_thing.a << std::endl; + things.push_back(the_thing); + } + } + break; + default: + break; + } + } + }; + fx(fx, lua); + + std::cout << std::endl; + + return 0; +} diff --git a/sol/optional_implementation.hpp b/sol/optional_implementation.hpp index 4ffd0f27..d036c3a6 100644 --- a/sol/optional_implementation.hpp +++ b/sol/optional_implementation.hpp @@ -771,15 +771,12 @@ namespace sol { } constexpr T& value() const { - return ref ? - *ref #ifdef SOL_NO_EXCEPTIONS - // we can't abort here - // because there's no constexpr abort - : *(T*)nullptr; + return *ref; #else - : throw bad_optional_access("bad optional access"); -#endif + return ref ? *ref + : (throw bad_optional_access("bad optional access"), *ref); +#endif // Exceptions } explicit constexpr operator bool() const noexcept {