Skip to content

Commit e5fab32

Browse files
committed
Merge remote-tracking branch 'origin/main' into shallow-value-category-on-move
2 parents ab3eedf + 5460182 commit e5fab32

File tree

3 files changed

+66
-9
lines changed

3 files changed

+66
-9
lines changed

include/beman/optional26/optional.hpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ class optional {
309309
requires(!std::is_trivially_destructible_v<T>);
310310

311311
// \ref{optional.assign}, assignment
312+
constexpr optional& operator=(nullopt_t) noexcept;
313+
312314
constexpr optional& operator=(const optional& rhs)
313315
requires std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T> &&
314316
(!std::is_trivially_copy_assignable_v<T>);
@@ -438,8 +440,7 @@ inline constexpr optional<T>::optional(const optional& rhs)
438440
requires std::is_copy_constructible_v<T> && (!std::is_trivially_copy_constructible_v<T>)
439441
{
440442
if (rhs.has_value()) {
441-
std::construct_at(std::addressof(value_), rhs.value_);
442-
engaged_ = true;
443+
construct(rhs.value_);
443444
}
444445
}
445446

@@ -448,8 +449,7 @@ inline constexpr optional<T>::optional(optional&& rhs) noexcept(std::is_nothrow_
448449
requires std::is_move_constructible_v<T> && (!std::is_trivially_move_constructible_v<T>)
449450
{
450451
if (rhs.has_value()) {
451-
std::construct_at(std::addressof(value_), std::move(rhs.value()));
452-
engaged_ = true;
452+
construct(std::move(rhs.value_));
453453
}
454454
}
455455

@@ -481,8 +481,7 @@ inline constexpr optional<T>::optional(const optional<U>& rhs)
481481
std::is_convertible_v<const U&, T>)
482482
{
483483
if (rhs.has_value()) {
484-
std::construct_at(std::addressof(value_), rhs.value());
485-
engaged_ = true;
484+
construct(*rhs);
486485
}
487486
}
488487

@@ -550,6 +549,12 @@ inline constexpr optional<T>::~optional()
550549

551550
// 22.5.3.4 Assignment[optional.assign]
552551

552+
template <class T>
553+
inline constexpr optional<T>& optional<T>::operator=(nullopt_t) noexcept {
554+
reset();
555+
return *this;
556+
}
557+
553558
template <class T>
554559
inline constexpr optional<T>& optional<T>::operator=(const optional<T>& rhs)
555560
requires std::is_copy_constructible_v<T> && std::is_copy_assignable_v<T> &&
@@ -560,7 +565,7 @@ inline constexpr optional<T>& optional<T>::operator=(const optional<T>& rhs)
560565
else if (has_value())
561566
value_ = rhs.value_;
562567
else
563-
std::construct_at(std::addressof(value_), rhs.value_);
568+
construct(rhs.value_);
564569
return *this;
565570
}
566571

@@ -575,7 +580,7 @@ optional<T>::operator=(optional<T>&& rhs) noexcept(std::is_nothrow_move_construc
575580
else if (has_value())
576581
value_ = std::move(rhs.value_);
577582
else
578-
std::construct_at(std::addressof(value_), std::move(rhs.value_));
583+
construct(std::move(rhs.value_));
579584
return *this;
580585
}
581586

src/beman/optional26/tests/optional.t.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,38 @@ TEST(OptionalTest, AssignmentValue) {
208208
*/
209209
beman::optional26::optional<not_trivial_copy_assignable> o5{5};
210210
beman::optional26::optional<not_trivial_copy_assignable> o6;
211+
212+
// Copy into empty optional.
211213
o6 = o5;
212-
EXPECT_TRUE(o5->i_ == 5);
214+
EXPECT_TRUE(o6);
215+
EXPECT_TRUE(o6->i_ == 5);
216+
217+
// Move into empty optional.
218+
o6.reset();
219+
o6 = std::move(o5);
220+
EXPECT_TRUE(o6);
221+
EXPECT_TRUE(o6->i_ == 5);
222+
223+
// Copy into engaged optional.
224+
beman::optional26::optional<not_trivial_copy_assignable> o7{7};
225+
o6 = o7;
226+
EXPECT_TRUE(o6);
227+
EXPECT_TRUE(o6->i_ == 7);
228+
229+
// Move into engaged optional.
230+
beman::optional26::optional<not_trivial_copy_assignable> o8{8};
231+
o6 = std::move(o8);
232+
EXPECT_TRUE(o6);
233+
EXPECT_TRUE(o6->i_ == 8);
234+
235+
// Copy from empty into engaged optional.
236+
o5.reset();
237+
o7 = o5;
238+
EXPECT_FALSE(o7);
239+
240+
// Move from empty into engaged optional.
241+
o8 = std::move(o5);
242+
EXPECT_FALSE(o8);
213243
}
214244

215245
TEST(OptionalTest, Triviality) {
@@ -869,6 +899,22 @@ TEST(OptionalTest, HashTest) {
869899
}
870900
}
871901

902+
TEST(OptionalTest, CanHoldValueOfImmovableType) {
903+
using beman::optional26::tests::immovable;
904+
905+
beman::optional26::optional<immovable> o1(beman::optional26::in_place);
906+
EXPECT_TRUE(o1);
907+
908+
// ...and can reset it with `nullopt`.
909+
static_assert(noexcept(o1 = beman::optional26::nullopt));
910+
o1 = beman::optional26::nullopt;
911+
EXPECT_FALSE(o1);
912+
913+
// Also, can construct with `nullopt`.
914+
beman::optional26::optional<immovable> o2 = beman::optional26::nullopt;
915+
EXPECT_FALSE(o2);
916+
}
917+
872918
// Moving an `optional<T&>` should not move the remote value.
873919
TEST(OptionalTest, OptionalFromOptionalRef) {
874920
using beman::optional26::tests::copyable_from_non_const_lvalue_only;

src/beman/optional26/tests/test_types.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ class Point {
6565
bool operator==(const Point&) const = default;
6666
};
6767

68+
struct immovable {
69+
explicit immovable() = default;
70+
immovable(const immovable&) = delete;
71+
immovable& operator=(const immovable&) = delete;
72+
};
73+
6874
struct copyable_from_non_const_lvalue_only {
6975
explicit copyable_from_non_const_lvalue_only() = default;
7076
copyable_from_non_const_lvalue_only(copyable_from_non_const_lvalue_only&) = default;

0 commit comments

Comments
 (0)