Skip to content

Commit 0174057

Browse files
authored
Merge pull request #109 from iris-cpp/fix-rvariant
Fix some bugs on rvariant for type-changing case
2 parents e195591 + 5d92999 commit 0174057

2 files changed

Lines changed: 65 additions & 13 deletions

File tree

‎include/iris/rvariant/rvariant.hpp‎

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -452,22 +452,15 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN
452452
this->template reset_construct_never_valueless<I>(std::forward<Args>(args)...);
453453

454454
} else {
455-
this->raw_visit([&, this]<std::size_t old_i, class T_old_i>(std::in_place_index_t<old_i>, T_old_i& t_old_i)
456-
noexcept(std::is_nothrow_constructible_v<T, Args...>)
457-
{
455+
this->raw_visit([&, this]<std::size_t old_i, class T_old_i>(std::in_place_index_t<old_i>, T_old_i& t_old_i) {
458456
static_assert(!std::is_reference_v<T_old_i>);
459457
static_assert(!std::is_const_v<T_old_i>);
460458

461459
if constexpr (old_i == std::variant_npos) {
462460
(void)t_old_i;
463461
this->template construct_on_valueless<I>(std::forward<Args>(args)...);
464462

465-
} else if constexpr (std::is_nothrow_constructible_v<T, Args...>) {
466-
t_old_i.~T_old_i();
467-
static_assert(std::is_nothrow_constructible_v<storage_type, std::in_place_index_t<old_i>, Args...>);
468-
std::construct_at(&this->storage_, std::in_place_index<old_i>, std::forward<Args>(args)...);
469-
470-
} else if constexpr (std::is_same_v<T_old_i, T>) { // NOT type-changing
463+
} else if constexpr (old_i == I) { // same alternative
471464
if constexpr (
472465
(sizeof(T) <= detail::never_valueless_trivial_size_limit && std::is_trivially_move_assignable_v<T>) ||
473466
is_recursive_wrapper_v<T>
@@ -497,12 +490,12 @@ IRIS_RVARIANT_ALWAYS_THROWING_UNREACHABLE_BEGIN
497490
static_assert(!never_valueless);
498491
t_old_i.~T_old_i();
499492
this->index_ = detail::variant_npos<sizeof...(Ts)>;
500-
static_assert(!noexcept(std::construct_at(&this->storage(), std::in_place_index<old_i>, std::forward<Args>(args)...)));
501-
std::construct_at(&this->storage_, std::in_place_index<old_i>, std::forward<Args>(args)...); // may throw
502-
this->index_ = old_i;
493+
static_assert(!noexcept(std::construct_at(&this->storage(), std::in_place_index<I>, std::forward<Args>(args)...)));
494+
std::construct_at(&this->storage_, std::in_place_index<I>, std::forward<Args>(args)...); // may throw
495+
this->index_ = I;
503496
}
504497

505-
} else { // type-changing
498+
} else { // another alternative, possibly of the same type
506499
if constexpr (
507500
(sizeof(T) <= detail::never_valueless_trivial_size_limit && std::is_trivially_move_constructible_v<T>) ||
508501
is_recursive_wrapper_v<T>

‎test/rvariant/rvariant.cpp‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <exception>
1515
#include <initializer_list>
1616
#include <memory>
17+
#include <string>
1718
#include <type_traits>
1819
#include <utility>
1920
#include <variant>
@@ -1422,6 +1423,64 @@ TEST_CASE("emplace")
14221423
STATIC_REQUIRE(is_never_valueless<iris::rvariant<iris::recursive_wrapper<int>>>);
14231424

14241425
// ReSharper restore CppStaticAssertFailure
1426+
1427+
// `emplace<I>` must switch to the I-th alternative even when the current one has the same type
1428+
{
1429+
// NOLINTBEGIN(modernize-use-equals-default)
1430+
{
1431+
struct S
1432+
{
1433+
S(int value) noexcept(false) : value(value) {} // potentially-throwing
1434+
int value = 0;
1435+
};
1436+
iris::rvariant<S, S> v(std::in_place_index<0>, 1);
1437+
v.emplace<1>(2);
1438+
REQUIRE(v.index() == 1);
1439+
CHECK(iris::get<1>(v).value == 2);
1440+
v.emplace<0>(3);
1441+
REQUIRE(v.index() == 0);
1442+
CHECK(iris::get<0>(v).value == 3);
1443+
}
1444+
{
1445+
struct StrangeS
1446+
{
1447+
StrangeS(int value) noexcept(false) : value(value) {} // potentially-throwing
1448+
StrangeS(StrangeS&& other) noexcept : value(other.value) {} // not trivial
1449+
StrangeS(StrangeS const&) = default; // trivial
1450+
StrangeS& operator=(StrangeS&& other) noexcept { value = other.value; return *this; } // not trivial
1451+
StrangeS& operator=(StrangeS const&) = default; // trivial
1452+
int value = 0;
1453+
};
1454+
iris::rvariant<StrangeS, StrangeS> v(std::in_place_index<0>, 1);
1455+
v.emplace<1>(2);
1456+
REQUIRE(v.index() == 1);
1457+
CHECK(iris::get<1>(v).value == 2);
1458+
v.emplace<0>(3);
1459+
REQUIRE(v.index() == 0);
1460+
CHECK(iris::get<0>(v).value == 3);
1461+
}
1462+
// NOLINTEND(modernize-use-equals-default)
1463+
{
1464+
iris::rvariant<std::string, std::string> v(std::in_place_index<0>, "a");
1465+
v.emplace<1>("b");
1466+
REQUIRE(v.index() == 1);
1467+
CHECK(iris::get<1>(v) == "b");
1468+
v.emplace<0>("c");
1469+
REQUIRE(v.index() == 0);
1470+
CHECK(iris::get<0>(v) == "c");
1471+
}
1472+
{
1473+
iris::rvariant<iris::recursive_wrapper<int>, iris::recursive_wrapper<int>> v(std::in_place_index<0>, 1);
1474+
v.emplace<1>(2);
1475+
REQUIRE(v.index() == 1);
1476+
CHECK(iris::get<1>(v) == 2);
1477+
}
1478+
STATIC_CHECK([] {
1479+
iris::rvariant<std::string, std::string> v(std::in_place_index<0>, "a");
1480+
v.emplace<1>("b");
1481+
return v.index() == 1 && iris::get<1>(v) == "b";
1482+
}());
1483+
}
14251484
}
14261485

14271486

0 commit comments

Comments
 (0)