template<typename E, typename T>
typename T::value_type value_or_throw(T&& value);
-// As above for with `prefix` added to the error message.
+// Like above for with `prefix` added to the error message.
template<typename E, typename T>
typename T::value_type value_or_throw(const T& value, std::string_view prefix);
template<typename E, typename T>
typename T::value_type value_or_throw(T&& value, std::string_view prefix);
+// Throw an exception of type `E` with a `T::error_type` as the argument if
+// `value` is false.
+template<typename E, typename T> void throw_on_error(const T& value);
+
+// Like above for with `prefix` added to the error message.
+template<typename E, typename T>
+void throw_on_error(const T& value, std::string_view prefix);
+
#define TRY(x_) \
do { \
const auto result = x_; \
}
}
+template<typename E, typename T>
+inline void
+throw_on_error(const T& value)
+{
+ if (!value) {
+ throw E(value.error());
+ }
+}
+
+// Like above for with `prefix` added to the error message.
+template<typename E, typename T>
+inline void
+throw_on_error(const T& value, std::string_view prefix)
+{
+ if (!value) {
+ throw E(FMT("{}{}", prefix, value.error()));
+ }
+}
+
} // namespace util
TEST_CASE("util::value_or_throw")
{
+ using util::throw_on_error;
using util::value_or_throw;
SUBCASE("const ref")
{
const nonstd::expected<int, const char*> with_value = 42;
- const nonstd::expected<int, const char*> without_value =
+ const nonstd::expected<int, const char*> with_error =
nonstd::make_unexpected("no value");
CHECK(value_or_throw<TestException>(with_value) == 42);
- CHECK_THROWS_WITH(value_or_throw<TestException>(without_value), "no value");
+ CHECK_THROWS_WITH(value_or_throw<TestException>(with_error), "no value");
}
SUBCASE("move")
const std::string value = "value";
nonstd::expected<std::unique_ptr<std::string>, const char*> with_value =
std::make_unique<std::string>(value);
- const nonstd::expected<int, const char*> without_value =
+ const nonstd::expected<int, const char*> with_error =
nonstd::make_unexpected("no value");
CHECK(*value_or_throw<TestException>(std::move(with_value)) == value);
- CHECK_THROWS_WITH(value_or_throw<TestException>(std::move(without_value)),
+ CHECK_THROWS_WITH(value_or_throw<TestException>(std::move(with_error)),
"no value");
}
SUBCASE("const ref with prefix")
{
const nonstd::expected<int, const char*> with_value = 42;
- const nonstd::expected<int, const char*> without_value =
+ const nonstd::expected<int, const char*> with_error =
nonstd::make_unexpected("no value");
CHECK(value_or_throw<TestException>(with_value, "prefix: ") == 42);
- CHECK_THROWS_WITH(value_or_throw<TestException>(without_value, "prefix: "),
+ CHECK_THROWS_WITH(value_or_throw<TestException>(with_error, "prefix: "),
"prefix: no value");
}
const std::string value = "value";
nonstd::expected<std::unique_ptr<std::string>, const char*> with_value =
std::make_unique<std::string>(value);
- const nonstd::expected<int, const char*> without_value =
+ const nonstd::expected<int, const char*> with_error =
nonstd::make_unexpected("no value");
CHECK(*value_or_throw<TestException>(std::move(with_value), "prefix: ")
== value);
CHECK_THROWS_WITH(
- value_or_throw<TestException>(std::move(without_value), "prefix: "),
+ value_or_throw<TestException>(std::move(with_error), "prefix: "),
"prefix: no value");
}
+
+ SUBCASE("void T::value_type")
+ {
+ const nonstd::expected<void, const char*> without_error;
+ const nonstd::expected<void, const char*> with_error =
+ nonstd::make_unexpected("no value");
+
+ CHECK_NOTHROW(throw_on_error<TestException>(without_error));
+ CHECK_THROWS_WITH(throw_on_error<TestException>(with_error), "no value");
+ }
+
+ SUBCASE("void T::value_type with prefix")
+ {
+ const nonstd::expected<void, const char*> without_error;
+ const nonstd::expected<void, const char*> with_error =
+ nonstd::make_unexpected("no value");
+
+ CHECK_NOTHROW(throw_on_error<TestException>(without_error, "prefix: "));
+ CHECK_THROWS_WITH(throw_on_error<TestException>(with_error, "prefix: "),
+ "prefix: no value");
+ }
}