Skip to content

Commit bee18d8

Browse files
committed
Fix assignment of related optional
Fix assignment operator for assign from optional<U> where U is something that can be bound to a T&. Delete the assignment from an rvalue ref as there is nothing to move and taking the pointer to temp will dangle.
1 parent 571f38d commit bee18d8

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

include/Beman/Optional26/optional.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1072,10 +1072,16 @@ class optional<T&> {
10721072
template <class U>
10731073
constexpr optional& operator=(const optional<U>& rhs) noexcept {
10741074
static_assert(std::is_constructible_v<std::add_lvalue_reference_t<T>, U>, "Must be able to bind U to T&");
1075-
value_ = std::addressof(rhs.value());
1075+
if (rhs.has_value())
1076+
value_ = std::to_address(rhs);
1077+
else
1078+
value_ = nullptr;
10761079
return *this;
10771080
}
10781081

1082+
template <class U>
1083+
constexpr optional& operator=(optional<U>&& rhs) = delete;
1084+
10791085
template <class U>
10801086
requires(!detail::is_optional<std::decay_t<U>>)
10811087
constexpr optional& emplace(U&& u) noexcept {

src/Beman/Optional26/tests/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ target_sources(
1818
optional_ref_monadic.t.cpp
1919
optional_ref.t.cpp
2020
optional.t.cpp
21-
optional_constexpr.t.cpp)
21+
optional_constexpr.t.cpp
22+
test_types.cpp)
2223

2324
target_link_libraries(
2425
beman_optional26_test

src/Beman/Optional26/tests/optional_ref.t.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,3 +553,70 @@ TEST(OptionalRefTest, SwapNullIntializedWithValue) {
553553
EXPECT_EQ(o1.value(), 42);
554554
EXPECT_TRUE(!o2.has_value());
555555
}
556+
557+
TEST(OptionalRefTest, AssignFromOptional) {
558+
int var = 42;
559+
beman::optional26::optional<int&> o1 = beman::optional26::nullopt;
560+
beman::optional26::optional<int&> o2 = var;
561+
562+
o2 = o1;
563+
564+
using beman::optional26::tests::base;
565+
using beman::optional26::tests::derived;
566+
567+
base b{1};
568+
derived d(1, 2);
569+
beman::optional26::optional<base&> empty_base;
570+
beman::optional26::optional<base&> engaged_base{b};
571+
572+
beman::optional26::optional<derived&> empty_derived_ref;
573+
beman::optional26::optional<derived&> engaged_derived_ref{d};
574+
575+
beman::optional26::optional<base&> optional_base_ref;
576+
optional_base_ref = empty_base;
577+
EXPECT_FALSE(optional_base_ref.has_value());
578+
optional_base_ref = engaged_base;
579+
EXPECT_TRUE(optional_base_ref.has_value());
580+
581+
optional_base_ref = empty_derived_ref;
582+
EXPECT_FALSE(optional_base_ref.has_value());
583+
584+
optional_base_ref = engaged_derived_ref;
585+
EXPECT_TRUE(optional_base_ref.has_value());
586+
587+
beman::optional26::optional<derived> empty_derived;
588+
beman::optional26::optional<derived> engaged_derived{d};
589+
590+
static_assert(std::is_constructible_v<const base&, derived>);
591+
592+
beman::optional26::optional<const base&> optional_base_const_ref;
593+
optional_base_const_ref = empty_derived;
594+
EXPECT_FALSE(optional_base_const_ref.has_value());
595+
596+
optional_base_const_ref = engaged_derived;
597+
EXPECT_TRUE(optional_base_const_ref.has_value());
598+
599+
if (empty_derived) {
600+
optional_base_ref = empty_derived.value();
601+
} else {
602+
optional_base_ref.reset();
603+
}
604+
EXPECT_FALSE(optional_base_ref.has_value());
605+
606+
if (engaged_derived) {
607+
optional_base_ref = engaged_derived.value();
608+
} else {
609+
optional_base_ref.reset();
610+
}
611+
EXPECT_TRUE(optional_base_ref.has_value());
612+
613+
derived d2(2, 2);
614+
engaged_derived = d2;
615+
EXPECT_EQ(optional_base_ref.value().m_i, static_cast<base>(d2).m_i);
616+
617+
// delete the rvalue ref overload
618+
// optional_base_const_ref = beman::optional26::optional<derived>(derived(3, 4));
619+
// EXPECT_TRUE(optional_base_ref.has_value());
620+
// EXPECT_EQ(*optional_base_ref, derived(3,4));
621+
622+
}

src/Beman/Optional26/tests/test_types.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#ifndef BEMAN_OPTIONAL26_TESTS_TEST_TYPES_HPP
55
#define BEMAN_OPTIONAL26_TESTS_TEST_TYPES_HPP
66

7+
#include <compare>
8+
79
namespace beman::optional26::tests {
810
// Classes used in the tests.
911

@@ -31,13 +33,20 @@ struct base {
3133
int m_i;
3234
constexpr base() : m_i(0) {}
3335
constexpr base(int i) : m_i(i) {}
36+
37+
bool operator!=(const base&) const = default;
38+
auto operator<=>(const base&) const = default;
39+
3440
};
3541

3642
// Derived class helper.
3743
struct derived : public base {
3844
int m_j;
3945
constexpr derived() : base(), m_j(0) {}
4046
constexpr derived(int i, int j) : base(i), m_j(j) {}
47+
48+
bool operator!=(const derived&) const = default;
49+
auto operator<=>(const derived&) const = default;
4150
};
4251

4352
} // namespace beman::optional26::tests

0 commit comments

Comments
 (0)