Sendit support optional<T&> and Result<T&, E>
This commit is contained in:
parent
293f4d1593
commit
c9826616b5
@ -1,6 +1,7 @@
|
|||||||
#ifndef OPTIONAL_HPP
|
#ifndef OPTIONAL_HPP
|
||||||
#define OPTIONAL_HPP
|
#define OPTIONAL_HPP
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -14,14 +15,27 @@ namespace detail {
|
|||||||
|
|
||||||
static constexpr nullopt_t nullopt;
|
static constexpr nullopt_t nullopt;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename T,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_same<typename std::decay<T>::type, void>::value && !std::is_rvalue_reference<T>::value,
|
||||||
|
int
|
||||||
|
>::type = 0
|
||||||
|
>
|
||||||
|
using well_behaved = std::conditional_t<
|
||||||
|
std::is_reference<T>::value, std::reference_wrapper<std::remove_reference_t<T>>, T
|
||||||
|
>;
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename T,
|
typename T,
|
||||||
typename std::enable_if<!std::is_same<typename std::decay<T>::type, void>::value, int>::type = 0
|
typename std::enable_if<!std::is_same<typename std::decay<T>::type, void>::value, int>::type = 0
|
||||||
>
|
>
|
||||||
class optional {
|
class optional {
|
||||||
|
using value_type = well_behaved<T>;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
char x;
|
char x;
|
||||||
T uvalue;
|
value_type uvalue;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool holds_value = false;
|
bool holds_value = false;
|
||||||
@ -37,16 +51,16 @@ namespace detail {
|
|||||||
|
|
||||||
optional(const optional& other) : holds_value(other.holds_value) {
|
optional(const optional& other) : holds_value(other.holds_value) {
|
||||||
if(holds_value) {
|
if(holds_value) {
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(other.uvalue);
|
new (static_cast<void*>(std::addressof(uvalue))) value_type(other.uvalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional(optional&& other)
|
optional(optional&& other)
|
||||||
noexcept(std::is_nothrow_move_constructible<T>::value)
|
noexcept(std::is_nothrow_move_constructible<value_type>::value)
|
||||||
: holds_value(other.holds_value)
|
: holds_value(other.holds_value)
|
||||||
{
|
{
|
||||||
if(holds_value) {
|
if(holds_value) {
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
new (static_cast<void*>(std::addressof(uvalue))) value_type(std::move(other.uvalue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,11 +71,11 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
optional& operator=(optional&& other)
|
optional& operator=(optional&& other)
|
||||||
noexcept(std::is_nothrow_move_assignable<T>::value && std::is_nothrow_move_constructible<T>::value)
|
noexcept(std::is_nothrow_move_assignable<value_type>::value && std::is_nothrow_move_constructible<value_type>::value)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
if(other.holds_value) {
|
if(other.holds_value) {
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
new (static_cast<void*>(std::addressof(uvalue))) value_type(std::move(other.uvalue));
|
||||||
holds_value = true;
|
holds_value = true;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@ -72,7 +86,7 @@ namespace detail {
|
|||||||
typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0
|
typename std::enable_if<!std::is_same<typename std::decay<U>::type, optional<T>>::value, int>::type = 0
|
||||||
>
|
>
|
||||||
optional(U&& value) : holds_value(true) {
|
optional(U&& value) : holds_value(true) {
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::forward<U>(value));
|
new (static_cast<void*>(std::addressof(uvalue))) value_type(std::forward<U>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
@ -94,11 +108,11 @@ namespace detail {
|
|||||||
if(holds_value && other.holds_value) {
|
if(holds_value && other.holds_value) {
|
||||||
std::swap(uvalue, other.uvalue);
|
std::swap(uvalue, other.uvalue);
|
||||||
} else if(holds_value && !other.holds_value) {
|
} else if(holds_value && !other.holds_value) {
|
||||||
new (&other.uvalue) T(std::move(uvalue));
|
new (&other.uvalue) value_type(std::move(uvalue));
|
||||||
uvalue.~T();
|
uvalue.~value_type();
|
||||||
} else if(!holds_value && other.holds_value) {
|
} else if(!holds_value && other.holds_value) {
|
||||||
new (static_cast<void*>(std::addressof(uvalue))) T(std::move(other.uvalue));
|
new (static_cast<void*>(std::addressof(uvalue))) value_type(std::move(other.uvalue));
|
||||||
other.uvalue.~T();
|
other.uvalue.~value_type();
|
||||||
}
|
}
|
||||||
std::swap(holds_value, other.holds_value);
|
std::swap(holds_value, other.holds_value);
|
||||||
}
|
}
|
||||||
@ -113,7 +127,7 @@ namespace detail {
|
|||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
if(holds_value) {
|
if(holds_value) {
|
||||||
uvalue.~T();
|
uvalue.~value_type();
|
||||||
}
|
}
|
||||||
holds_value = false;
|
holds_value = false;
|
||||||
}
|
}
|
||||||
@ -140,12 +154,12 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
NODISCARD T value_or(U&& default_value) const & {
|
NODISCARD T value_or(U&& default_value) const & {
|
||||||
return holds_value ? uvalue : static_cast<T>(std::forward<U>(default_value));
|
return holds_value ? static_cast<T>(uvalue) : static_cast<T>(std::forward<U>(default_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
NODISCARD T value_or(U&& default_value) && {
|
NODISCARD T value_or(U&& default_value) && {
|
||||||
return holds_value ? std::move(uvalue) : static_cast<T>(std::forward<U>(default_value));
|
return holds_value ? static_cast<T>(std::move(uvalue)) : static_cast<T>(std::forward<U>(default_value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,20 +13,21 @@ namespace cpptrace {
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
template<typename T, typename E, typename std::enable_if<!std::is_same<T, E>::value, int>::type = 0>
|
template<typename T, typename E, typename std::enable_if<!std::is_same<T, E>::value, int>::type = 0>
|
||||||
class Result {
|
class Result {
|
||||||
|
using value_type = well_behaved<T>;
|
||||||
union {
|
union {
|
||||||
T value_;
|
value_type value_;
|
||||||
E error_;
|
E error_;
|
||||||
};
|
};
|
||||||
enum class member { value, error };
|
enum class member { value, error };
|
||||||
member active;
|
member active;
|
||||||
public:
|
public:
|
||||||
Result(T&& value) : value_(std::move(value)), active(member::value) {}
|
Result(value_type&& value) : value_(std::move(value)), active(member::value) {}
|
||||||
Result(E&& error) : error_(std::move(error)), active(member::error) {
|
Result(E&& error) : error_(std::move(error)), active(member::error) {
|
||||||
if(!should_absorb_trace_exceptions()) {
|
if(!should_absorb_trace_exceptions()) {
|
||||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Result(T& value) : value_(T(value)), active(member::value) {}
|
Result(value_type& value) : value_(value_type(value)), active(member::value) {}
|
||||||
Result(E& error) : error_(E(error)), active(member::error) {
|
Result(E& error) : error_(E(error)), active(member::error) {
|
||||||
if(!should_absorb_trace_exceptions()) {
|
if(!should_absorb_trace_exceptions()) {
|
||||||
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
std::fprintf(stderr, "%s\n", unwrap_error().what());
|
||||||
@ -34,14 +35,14 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
Result(Result&& other) : active(other.active) {
|
Result(Result&& other) : active(other.active) {
|
||||||
if(other.active == member::value) {
|
if(other.active == member::value) {
|
||||||
new (&value_) T(std::move(other.value_));
|
new (&value_) value_type(std::move(other.value_));
|
||||||
} else {
|
} else {
|
||||||
new (&error_) E(std::move(other.error_));
|
new (&error_) E(std::move(other.error_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~Result() {
|
~Result() {
|
||||||
if(active == member::value) {
|
if(active == member::value) {
|
||||||
value_.~T();
|
value_.~value_type();
|
||||||
} else {
|
} else {
|
||||||
error_.~E();
|
error_.~E();
|
||||||
}
|
}
|
||||||
@ -107,12 +108,12 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
NODISCARD T value_or(U&& default_value) const & {
|
NODISCARD T value_or(U&& default_value) const & {
|
||||||
return has_value() ? value_ : static_cast<T>(std::forward<U>(default_value));
|
return has_value() ? static_cast<T>(value_) : static_cast<T>(std::forward<U>(default_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
NODISCARD T value_or(U&& default_value) && {
|
NODISCARD T value_or(U&& default_value) && {
|
||||||
return has_value() ? std::move(value_) : static_cast<T>(std::forward<U>(default_value));
|
return has_value() ? static_cast<T>(std::move(value_)) : static_cast<T>(std::forward<U>(default_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void drop_error() const {
|
void drop_error() const {
|
||||||
|
|||||||
@ -11,11 +11,19 @@ TEST(OptionalTest, DefaultConstructor) {
|
|||||||
optional<int> o;
|
optional<int> o;
|
||||||
EXPECT_FALSE(o.has_value());
|
EXPECT_FALSE(o.has_value());
|
||||||
EXPECT_FALSE(static_cast<bool>(o));
|
EXPECT_FALSE(static_cast<bool>(o));
|
||||||
|
|
||||||
|
optional<int&> o1;
|
||||||
|
EXPECT_FALSE(o1.has_value());
|
||||||
|
EXPECT_FALSE(static_cast<bool>(o1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, ConstructWithNullopt) {
|
TEST(OptionalTest, ConstructWithNullopt) {
|
||||||
optional<int> o(nullopt);
|
optional<int> o(nullopt);
|
||||||
EXPECT_FALSE(o.has_value());
|
EXPECT_FALSE(o.has_value());
|
||||||
|
|
||||||
|
optional<int&> o1(nullopt);
|
||||||
|
EXPECT_FALSE(o1.has_value());
|
||||||
|
EXPECT_FALSE(static_cast<bool>(o1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, ValueConstructor) {
|
TEST(OptionalTest, ValueConstructor) {
|
||||||
@ -27,6 +35,13 @@ TEST(OptionalTest, ValueConstructor) {
|
|||||||
optional<int> o2(x);
|
optional<int> o2(x);
|
||||||
EXPECT_TRUE(o2.has_value());
|
EXPECT_TRUE(o2.has_value());
|
||||||
EXPECT_EQ(o2.unwrap(), 100);
|
EXPECT_EQ(o2.unwrap(), 100);
|
||||||
|
|
||||||
|
int y = 100;
|
||||||
|
optional<int&> o3(y);
|
||||||
|
EXPECT_TRUE(o3.has_value());
|
||||||
|
EXPECT_EQ(o3.unwrap(), 100);
|
||||||
|
y = 200;
|
||||||
|
EXPECT_EQ(o3.unwrap(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, CopyConstructor) {
|
TEST(OptionalTest, CopyConstructor) {
|
||||||
@ -38,6 +53,17 @@ TEST(OptionalTest, CopyConstructor) {
|
|||||||
optional<int> o3(nullopt);
|
optional<int> o3(nullopt);
|
||||||
optional<int> o4(o3);
|
optional<int> o4(o3);
|
||||||
EXPECT_FALSE(o4.has_value());
|
EXPECT_FALSE(o4.has_value());
|
||||||
|
|
||||||
|
int y = 100;
|
||||||
|
optional<int&> o5(y);
|
||||||
|
optional<int&> o6(o5);
|
||||||
|
EXPECT_TRUE(o5.has_value());
|
||||||
|
EXPECT_EQ(o5.unwrap(), 100);
|
||||||
|
EXPECT_TRUE(o6.has_value());
|
||||||
|
EXPECT_EQ(o6.unwrap(), 100);
|
||||||
|
y = 200;
|
||||||
|
EXPECT_EQ(o5.unwrap(), 200);
|
||||||
|
EXPECT_EQ(o6.unwrap(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, MoveConstructor) {
|
TEST(OptionalTest, MoveConstructor) {
|
||||||
@ -49,6 +75,14 @@ TEST(OptionalTest, MoveConstructor) {
|
|||||||
optional<int> o3(nullopt);
|
optional<int> o3(nullopt);
|
||||||
optional<int> o4(std::move(o3));
|
optional<int> o4(std::move(o3));
|
||||||
EXPECT_FALSE(o4.has_value());
|
EXPECT_FALSE(o4.has_value());
|
||||||
|
|
||||||
|
int y = 100;
|
||||||
|
optional<int&> o5(y);
|
||||||
|
optional<int&> o6(std::move(o5));
|
||||||
|
EXPECT_TRUE(o6.has_value());
|
||||||
|
EXPECT_EQ(o6.unwrap(), 100);
|
||||||
|
y = 200;
|
||||||
|
EXPECT_EQ(o6.unwrap(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, CopyAssignmentOperator) {
|
TEST(OptionalTest, CopyAssignmentOperator) {
|
||||||
@ -62,6 +96,18 @@ TEST(OptionalTest, CopyAssignmentOperator) {
|
|||||||
optional<int> o4(100);
|
optional<int> o4(100);
|
||||||
o4 = o3;
|
o4 = o3;
|
||||||
EXPECT_FALSE(o4.has_value());
|
EXPECT_FALSE(o4.has_value());
|
||||||
|
|
||||||
|
int y = 100;
|
||||||
|
optional<int&> o5(y);
|
||||||
|
optional<int&> o6;
|
||||||
|
o6 = o5;
|
||||||
|
EXPECT_TRUE(o5.has_value());
|
||||||
|
EXPECT_EQ(o5.unwrap(), 100);
|
||||||
|
EXPECT_TRUE(o6.has_value());
|
||||||
|
EXPECT_EQ(o6.unwrap(), 100);
|
||||||
|
y = 200;
|
||||||
|
EXPECT_EQ(o5.unwrap(), 200);
|
||||||
|
EXPECT_EQ(o6.unwrap(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, MoveAssignmentOperator) {
|
TEST(OptionalTest, MoveAssignmentOperator) {
|
||||||
@ -75,6 +121,15 @@ TEST(OptionalTest, MoveAssignmentOperator) {
|
|||||||
optional<int> o4(99);
|
optional<int> o4(99);
|
||||||
o4 = std::move(o3);
|
o4 = std::move(o3);
|
||||||
EXPECT_FALSE(o4.has_value());
|
EXPECT_FALSE(o4.has_value());
|
||||||
|
|
||||||
|
int y = 100;
|
||||||
|
optional<int&> o5(y);
|
||||||
|
optional<int&> o6;
|
||||||
|
o6 = std::move(o5);
|
||||||
|
EXPECT_TRUE(o6.has_value());
|
||||||
|
EXPECT_EQ(o6.unwrap(), 100);
|
||||||
|
y = 200;
|
||||||
|
EXPECT_EQ(o6.unwrap(), 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, AssignmentFromValue) {
|
TEST(OptionalTest, AssignmentFromValue) {
|
||||||
@ -85,13 +140,31 @@ TEST(OptionalTest, AssignmentFromValue) {
|
|||||||
|
|
||||||
o = nullopt;
|
o = nullopt;
|
||||||
EXPECT_FALSE(o.has_value());
|
EXPECT_FALSE(o.has_value());
|
||||||
|
|
||||||
|
optional<int&> o1;
|
||||||
|
int x = 100;
|
||||||
|
o1 = x;
|
||||||
|
EXPECT_TRUE(o1.has_value());
|
||||||
|
EXPECT_EQ(o1.unwrap(), x);
|
||||||
|
EXPECT_EQ(&o1.unwrap(), &x);
|
||||||
|
|
||||||
|
o1 = nullopt;
|
||||||
|
EXPECT_FALSE(o1.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, Reset) {
|
TEST(OptionalTest, Reset) {
|
||||||
optional<int> o(42);
|
optional<int> o(42);
|
||||||
EXPECT_TRUE(o.has_value());
|
EXPECT_TRUE(o.has_value());
|
||||||
|
EXPECT_EQ(o.unwrap(), 42);
|
||||||
o.reset();
|
o.reset();
|
||||||
EXPECT_FALSE(o.has_value());
|
EXPECT_FALSE(o.has_value());
|
||||||
|
|
||||||
|
int x = 44;
|
||||||
|
optional<int&> o1(x);
|
||||||
|
EXPECT_TRUE(o1.has_value());
|
||||||
|
EXPECT_EQ(o1.unwrap(), 44);
|
||||||
|
o1.reset();
|
||||||
|
EXPECT_FALSE(o1.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, Swap) {
|
TEST(OptionalTest, Swap) {
|
||||||
@ -111,6 +184,18 @@ TEST(OptionalTest, Swap) {
|
|||||||
EXPECT_FALSE(o3.has_value());
|
EXPECT_FALSE(o3.has_value());
|
||||||
EXPECT_TRUE(o4.has_value());
|
EXPECT_TRUE(o4.has_value());
|
||||||
EXPECT_EQ(o4.unwrap(), 7);
|
EXPECT_EQ(o4.unwrap(), 7);
|
||||||
|
|
||||||
|
int x = 20;
|
||||||
|
int y = 40;
|
||||||
|
optional<int&> o5 = x;
|
||||||
|
optional<int&> o6 = y;
|
||||||
|
EXPECT_EQ(o5.unwrap(), 20);
|
||||||
|
EXPECT_EQ(o6.unwrap(), 40);
|
||||||
|
o5.swap(o6);
|
||||||
|
EXPECT_EQ(o5.unwrap(), 40);
|
||||||
|
EXPECT_EQ(o6.unwrap(), 20);
|
||||||
|
EXPECT_EQ(x, 20);
|
||||||
|
EXPECT_EQ(y, 40);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OptionalTest, ValueOr) {
|
TEST(OptionalTest, ValueOr) {
|
||||||
@ -119,6 +204,16 @@ TEST(OptionalTest, ValueOr) {
|
|||||||
|
|
||||||
optional<int> o2(nullopt);
|
optional<int> o2(nullopt);
|
||||||
EXPECT_EQ(o2.value_or(100), 100);
|
EXPECT_EQ(o2.value_or(100), 100);
|
||||||
|
|
||||||
|
int x = 20;
|
||||||
|
int y = 100;
|
||||||
|
optional<int&> o3(x);
|
||||||
|
EXPECT_EQ(o3.value_or(y), 20);
|
||||||
|
o3.reset();
|
||||||
|
EXPECT_EQ(o3.value_or(y), 100);
|
||||||
|
EXPECT_EQ(&o3.value_or(y), &y);
|
||||||
|
EXPECT_EQ(x, 20);
|
||||||
|
EXPECT_EQ(y, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,11 @@ TEST_F(ResultFixture, ConstructWithValueLValue) {
|
|||||||
|
|
||||||
s = "x";
|
s = "x";
|
||||||
EXPECT_EQ(result.unwrap_value(), "test");
|
EXPECT_EQ(result.unwrap_value(), "test");
|
||||||
|
|
||||||
|
cpptrace::detail::Result<std::string&, error> r2(s);
|
||||||
|
EXPECT_EQ(r2.unwrap_value(), "x");
|
||||||
|
s = "y";
|
||||||
|
EXPECT_EQ(r2.unwrap_value(), "y");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResultFixture, ConstructWithErrorRValue) {
|
TEST_F(ResultFixture, ConstructWithErrorRValue) {
|
||||||
@ -71,10 +76,18 @@ TEST_F(ResultFixture, ConstructWithErrorLValue) {
|
|||||||
TEST_F(ResultFixture, MoveConstructorValue) {
|
TEST_F(ResultFixture, MoveConstructorValue) {
|
||||||
cpptrace::detail::Result<std::string, error> original(std::string("move"));
|
cpptrace::detail::Result<std::string, error> original(std::string("move"));
|
||||||
cpptrace::detail::Result<std::string, error> moved(std::move(original));
|
cpptrace::detail::Result<std::string, error> moved(std::move(original));
|
||||||
|
|
||||||
EXPECT_TRUE(moved.has_value());
|
EXPECT_TRUE(moved.has_value());
|
||||||
EXPECT_EQ(moved.unwrap_value(), "move");
|
EXPECT_EQ(moved.unwrap_value(), "move");
|
||||||
EXPECT_TRUE(original.has_value());
|
EXPECT_TRUE(original.has_value());
|
||||||
|
|
||||||
|
std::string s = "test";
|
||||||
|
cpptrace::detail::Result<std::string&, error> r1(s);
|
||||||
|
cpptrace::detail::Result<std::string&, error> r2(std::move(r1));
|
||||||
|
EXPECT_TRUE(r2.has_value());
|
||||||
|
EXPECT_EQ(r2.unwrap_value(), "test");
|
||||||
|
s = "foo";
|
||||||
|
EXPECT_EQ(r2.unwrap_value(), "foo");
|
||||||
|
EXPECT_TRUE(r2.has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResultFixture, MoveConstructorError) {
|
TEST_F(ResultFixture, MoveConstructorError) {
|
||||||
@ -97,6 +110,20 @@ TEST_F(ResultFixture, ValueOr) {
|
|||||||
EXPECT_EQ(res_with_error.value_or(-1), -1);
|
EXPECT_EQ(res_with_error.value_or(-1), -1);
|
||||||
EXPECT_EQ(std::move(res_with_error).value_or(-1), -1);
|
EXPECT_EQ(std::move(res_with_error).value_or(-1), -1);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
int x = 2;
|
||||||
|
int y = 3;
|
||||||
|
cpptrace::detail::Result<int&, error> res_with_value(x);
|
||||||
|
EXPECT_EQ(res_with_value.value_or(y), 2);
|
||||||
|
EXPECT_EQ(std::move(res_with_value).value_or(y), 2);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
int x = 2;
|
||||||
|
cpptrace::detail::Result<int&, error> res_with_error(error{});
|
||||||
|
EXPECT_EQ(res_with_error.value_or(x), 2);
|
||||||
|
EXPECT_EQ(&res_with_error.value_or(x), &x);
|
||||||
|
EXPECT_EQ(std::move(res_with_error).value_or(x), 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user