Skip to content

Commit 5e7e83c

Browse files
committed
✨ Attach error with bad_result_access
The exception thrown during access to a `result` object previously simply contained a generic error message, but did not contain the error code. This doesn't lend much context to the actual error, which complicates identification by the user. The `std::expected` proposal for which this project was once based on throws an exception containing the `E` type, but derives from an exception containing the `void` type. This specialization of the exception is precisely what was being avoided by not doing this in the first place as part of this implementation. However, since designsh ave changed, it has become more apparent that it would be useful to attach the exact error type into the exception for the few cases that this will be used.
1 parent 3f5c849 commit 5e7e83c

2 files changed

Lines changed: 133 additions & 38 deletions

File tree

include/result.hpp

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ inline namespace bitwizeshift {
279279
template <typename, typename>
280280
class result;
281281

282+
template <typename>
282283
class bad_result_access;
283284

284285
//===========================================================================
@@ -315,28 +316,52 @@ inline namespace bitwizeshift {
315316
#if !defined(RESULT_DISABLE_EXCEPTIONS)
316317

317318
//===========================================================================
318-
// class : bad_result_access
319+
// class : bad_result_access<E>
319320
//===========================================================================
320321

321322
/////////////////////////////////////////////////////////////////////////////
322323
/// \brief An exception thrown when result::value is accessed without
323324
/// a contained value
324325
/////////////////////////////////////////////////////////////////////////////
326+
template <typename E>
325327
class bad_result_access : public std::logic_error
326328
{
327329
//-------------------------------------------------------------------------
328330
// Constructor / Assignment
329331
//-------------------------------------------------------------------------
330332
public:
331333

332-
bad_result_access();
334+
/// \brief Constructs this exception using the underlying error type for
335+
/// the error type
336+
///
337+
/// \param error the underlying error
338+
template <typename E2,
339+
typename = typename std::enable_if<std::is_constructible<E,E2>::value>::type>
340+
explicit bad_result_access(E2&& error);
333341
bad_result_access(const bad_result_access& other) = default;
334342
bad_result_access(bad_result_access&& other) = default;
335343

336344
//-------------------------------------------------------------------------
337345

338346
auto operator=(const bad_result_access& other) -> bad_result_access& = default;
339347
auto operator=(bad_result_access&& other) -> bad_result_access& = default;
348+
349+
/// \{
350+
/// \brief Gets the underlying error
351+
///
352+
/// \return the error
353+
auto error() & noexcept -> E&;
354+
auto error() && noexcept -> E&&;
355+
auto error() const & noexcept -> const E&;
356+
auto error() const && noexcept -> const E&&;
357+
/// \}
358+
359+
//-------------------------------------------------------------------------
360+
// Private Members
361+
//-------------------------------------------------------------------------
362+
private:
363+
364+
E m_error;
340365
};
341366

342367
#endif
@@ -1370,8 +1395,9 @@ inline namespace bitwizeshift {
13701395
template <typename T, typename E>
13711396
constexpr auto extract_error(const result<T,E>& exp) noexcept -> const E&;
13721397

1398+
template <typename E>
13731399
[[noreturn]]
1374-
auto throw_bad_result_access() -> void;
1400+
auto throw_bad_result_access(E&& error) -> void;
13751401

13761402
} // namespace detail
13771403

@@ -2452,10 +2478,13 @@ inline namespace bitwizeshift {
24522478

24532479
//-------------------------------------------------------------------------
24542480

2481+
/// \{
24552482
/// \brief Throws an exception if contains an error
24562483
///
24572484
/// \throws bad_result_access if `*this` contains an error.
2458-
RESULT_CPP14_CONSTEXPR auto value() const -> void;
2485+
RESULT_CPP14_CONSTEXPR auto value() && -> void;
2486+
RESULT_CPP14_CONSTEXPR auto value() const & -> void;
2487+
/// \}
24592488

24602489
/// \{
24612490
/// \brief Returns the contained error, if one exists, or a
@@ -2815,11 +2844,50 @@ namespace std {
28152844
// Constructors
28162845
//-----------------------------------------------------------------------------
28172846

2847+
template <typename E>
2848+
template <typename E2, typename>
2849+
inline RESULT_INLINE_VISIBILITY
2850+
RESULT_NS_IMPL::bad_result_access<E>::bad_result_access(E2&& error)
2851+
: logic_error{"error attempting to access value from result containing error"},
2852+
m_error(detail::forward<E2>(error))
2853+
{
2854+
2855+
}
2856+
2857+
//-----------------------------------------------------------------------------
2858+
// Observers
2859+
//-----------------------------------------------------------------------------
2860+
2861+
template <typename E>
2862+
inline RESULT_INLINE_VISIBILITY
2863+
auto RESULT_NS_IMPL::bad_result_access<E>::error()
2864+
& noexcept -> E&
2865+
{
2866+
return m_error;
2867+
}
2868+
2869+
template <typename E>
28182870
inline RESULT_INLINE_VISIBILITY
2819-
RESULT_NS_IMPL::bad_result_access::bad_result_access()
2820-
: logic_error{"bad_result_access"}
2871+
auto RESULT_NS_IMPL::bad_result_access<E>::error()
2872+
&& noexcept -> E&&
28212873
{
2874+
return static_cast<E&&>(m_error);
2875+
}
28222876

2877+
template <typename E>
2878+
inline RESULT_INLINE_VISIBILITY
2879+
auto RESULT_NS_IMPL::bad_result_access<E>::error()
2880+
const & noexcept -> const E&
2881+
{
2882+
return m_error;
2883+
}
2884+
2885+
template <typename E>
2886+
inline RESULT_INLINE_VISIBILITY
2887+
auto RESULT_NS_IMPL::bad_result_access<E>::error()
2888+
const && noexcept -> const E&&
2889+
{
2890+
return static_cast<const E&&>(m_error);
28232891
}
28242892

28252893
#endif
@@ -3531,14 +3599,23 @@ auto RESULT_NS_IMPL::detail::extract_error(const result<T,E>& exp) noexcept -> c
35313599
return result_error_extractor::get(exp);
35323600
}
35333601

3602+
template <typename E>
35343603
[[noreturn]]
35353604
inline RESULT_INLINE_VISIBILITY
3536-
auto RESULT_NS_IMPL::detail::throw_bad_result_access() -> void
3605+
auto RESULT_NS_IMPL::detail::throw_bad_result_access(E&& error) -> void
35373606
{
35383607
#if defined(RESULT_DISABLE_EXCEPTIONS)
35393608
std::abort();
35403609
#else
3541-
throw bad_result_access{};
3610+
using exception_type = bad_result_access<
3611+
typename std::remove_const<
3612+
typename std::remove_reference<E>::type
3613+
>::type
3614+
>;
3615+
3616+
throw exception_type{
3617+
detail::forward<E>(error)
3618+
};
35423619
#endif
35433620
}
35443621

@@ -3868,7 +3945,8 @@ inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
38683945
auto RESULT_NS_IMPL::result<T,E>::value()
38693946
& -> typename std::add_lvalue_reference<T>::type
38703947
{
3871-
return (has_value() || (detail::throw_bad_result_access(), false),
3948+
return (has_value() ||
3949+
(detail::throw_bad_result_access(m_storage.storage.m_error), false),
38723950
m_storage.storage.m_value
38733951
);
38743952
}
@@ -3880,7 +3958,8 @@ auto RESULT_NS_IMPL::result<T,E>::value()
38803958
{
38813959
using reference = typename std::add_rvalue_reference<T>::type;
38823960

3883-
return (has_value() || (detail::throw_bad_result_access(), true),
3961+
return (has_value() ||
3962+
(detail::throw_bad_result_access(static_cast<E&&>(m_storage.storage.m_error)), true),
38843963
static_cast<reference>(m_storage.storage.m_value)
38853964
);
38863965
}
@@ -3890,7 +3969,8 @@ inline RESULT_INLINE_VISIBILITY constexpr
38903969
auto RESULT_NS_IMPL::result<T,E>::value()
38913970
const & -> typename std::add_lvalue_reference<typename std::add_const<T>::type>::type
38923971
{
3893-
return (has_value() || (detail::throw_bad_result_access(), true),
3972+
return (has_value() ||
3973+
(detail::throw_bad_result_access(m_storage.storage.m_error), true),
38943974
m_storage.storage.m_value
38953975
);
38963976
}
@@ -3902,7 +3982,8 @@ auto RESULT_NS_IMPL::result<T,E>::value()
39023982
{
39033983
using reference = typename std::add_rvalue_reference<typename std::add_const<T>::type>::type;
39043984

3905-
return (has_value() || (detail::throw_bad_result_access(), true),
3985+
return (has_value() ||
3986+
(detail::throw_bad_result_access(static_cast<const E&&>(m_storage.storage.m_error)), true),
39063987
(static_cast<reference>(m_storage.storage.m_value))
39073988
);
39083989
}
@@ -4364,9 +4445,23 @@ auto RESULT_NS_IMPL::result<void, E>::has_error()
43644445
template <typename E>
43654446
inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
43664447
auto RESULT_NS_IMPL::result<void, E>::value()
4367-
const -> void
4448+
const & -> void
43684449
{
4369-
static_cast<void>(has_value() || (detail::throw_bad_result_access(), true));
4450+
static_cast<void>(
4451+
has_value() ||
4452+
(detail::throw_bad_result_access(m_storage.storage.m_error), true)
4453+
);
4454+
}
4455+
4456+
template <typename E>
4457+
inline RESULT_INLINE_VISIBILITY RESULT_CPP14_CONSTEXPR
4458+
auto RESULT_NS_IMPL::result<void, E>::value()
4459+
&& -> void
4460+
{
4461+
static_cast<void>(
4462+
has_value() ||
4463+
(detail::throw_bad_result_access(static_cast<E&&>(m_storage.storage.m_error)), true)
4464+
);
43704465
}
43714466

43724467
template <typename E>

0 commit comments

Comments
 (0)