diff --git a/Source/LuaBridge/detail/Expected.h b/Source/LuaBridge/detail/Expected.h index 36cab32e..246001dd 100644 --- a/Source/LuaBridge/detail/Expected.h +++ b/Source/LuaBridge/detail/Expected.h @@ -8,6 +8,7 @@ #include #include +#include #include #if LUABRIDGE_HAS_EXCEPTIONS @@ -62,6 +63,19 @@ struct is_nothrow_swappable : std::is_nothrow_swappable_with, std::add_lvalue_reference_t> { }; + +template +struct has_member_message : std::false_type +{ +}; + +template +struct has_member_message().message())>> : std::true_type +{ +}; + +template +inline static constexpr bool has_member_message_v = has_member_message::value; } // namespace detail template @@ -976,19 +990,41 @@ template class BadExpectedAccess; template <> -class BadExpectedAccess : public std::exception +class BadExpectedAccess : public std::runtime_error { + template + friend class BadExpectedAccess; + + BadExpectedAccess(std::in_place_t) noexcept + : std::runtime_error("Bad access to expected value") + { + } + public: - explicit BadExpectedAccess() noexcept + BadExpectedAccess() noexcept + : BadExpectedAccess(std::in_place) + { + } + + explicit BadExpectedAccess(const std::string& message) noexcept + : std::runtime_error(message) { } }; + template class BadExpectedAccess : public BadExpectedAccess { public: explicit BadExpectedAccess(E error) noexcept(std::is_nothrow_constructible_v) - : error_(std::move(error)) + : BadExpectedAccess([](const E& error) + { + if constexpr (detail::has_member_message_v) + return error.message(); + else + return std::in_place; + }(error)) + , error_(std::move(error)) { } diff --git a/Tests/Source/Tests.cpp b/Tests/Source/Tests.cpp index a11479cc..546ca442 100644 --- a/Tests/Source/Tests.cpp +++ b/Tests/Source/Tests.cpp @@ -874,6 +874,28 @@ TEST_F(LuaBridgeTest, BooleanNoValue) } #if LUABRIDGE_HAS_EXCEPTIONS +TEST_F(LuaBridgeTest, StackExceptionWithMessage) +{ + try { + auto result = luabridge::Stack::get(L, 1); + result.value(); + EXPECT_FALSE(true); + } catch (const std::exception& e) { + EXPECT_STREQ("The lua object can't be cast to desired type", e.what()); + } +} + +TEST_F(LuaBridgeTest, ExpectedExceptionWithoutMessage) +{ + try { + luabridge::Expected result = luabridge::makeUnexpected(5); + result.value(); + EXPECT_FALSE(true); + } catch (const std::exception& e) { + EXPECT_STREQ("bad_expected_access", e.what()); + } +} + namespace { template std::string call_callback_get_exception(const luabridge::LuaRef& fn, Args&&... args)