diff --git a/src/common/variant.h b/src/common/variant.h index 5b9a1753d..bc2da5dbf 100644 --- a/src/common/variant.h +++ b/src/common/variant.h @@ -87,15 +87,14 @@ struct variant_static_visitor : public boost::static_visitor }; template -class variant final +class variant { - using VType = boost::variant; + using VType = boost::variant; public: //constructors /// default constructor variant() = default; - variant(boost::none_t) : variant{} {} //act like boost::optional /// construct from variant type (use enable_if to avoid issues with copy/move constructor) template ::type = true> variant(T &&value) : m_value{std::forward(value)} {} -//overloaded operators - /// boolean operator: true if the variant isn't empty/uninitialized - explicit operator bool() const noexcept { return !this->is_empty(); } - //member functions - /// check if empty/uninitialized - bool is_empty() const noexcept { return m_value.which() == 0; } - /// check the variant type template bool is_type() const noexcept { return this->index() == this->type_index_of(); } @@ -149,7 +141,7 @@ public: template static constexpr int type_index_of() noexcept { - using types = boost::mpl::vector; + using types = typename VType::types; using elem = typename boost::mpl::find::type; using begin = typename boost::mpl::begin::type; return boost::mpl::distance::value; @@ -187,4 +179,35 @@ private: VType m_value; }; +template +class optional_variant: public variant +{ +public: +//constructors + /// default constructor + optional_variant() = default; + + /// construct from variant type (use enable_if to avoid issues with copy/move constructor) + template >, + optional_variant + >::value, + bool + >::type = true> + optional_variant(T &&value) : variant(std::forward(value)) {} + + // construct like boost::optional + optional_variant(boost::none_t) {} + +//overloaded operators + /// boolean operator: true if the variant isn't empty/uninitialized + explicit operator bool() const noexcept { return !this->is_empty(); } + +//member functions + /// check if empty/uninitialized + bool is_empty() const noexcept { return this->index() == 0; } +}; + } //namespace tools diff --git a/tests/unit_tests/variant.cpp b/tests/unit_tests/variant.cpp index 3b0c96c4f..3c82ebd50 100644 --- a/tests/unit_tests/variant.cpp +++ b/tests/unit_tests/variant.cpp @@ -38,6 +38,7 @@ #include #include +using tools::optional_variant; using tools::variant; using tools::variant_static_visitor; @@ -239,7 +240,7 @@ struct test_stringify_visitor: public variant_static_visitor //------------------------------------------------------------------------------------------------------------------- TEST(variant, operatorbool) { - variant v; + optional_variant v; EXPECT_FALSE(v); v = (int16_t) 2023; EXPECT_TRUE(v); @@ -251,7 +252,7 @@ TEST(variant, operatorbool) //------------------------------------------------------------------------------------------------------------------- TEST(variant, is_empty) { - variant v; + optional_variant v; EXPECT_TRUE(v.is_empty()); v = (int16_t) 2023; EXPECT_FALSE(v.is_empty()); @@ -260,7 +261,7 @@ TEST(variant, is_empty) v = boost::blank{}; EXPECT_TRUE(v.is_empty()); - variant<> v2; + optional_variant<> v2; EXPECT_TRUE(v2.is_empty()); v2 = boost::blank{}; EXPECT_TRUE(v2.is_empty()); @@ -269,7 +270,7 @@ TEST(variant, is_empty) TEST(variant, is_type) { variant v; - EXPECT_TRUE(v.is_type()); + EXPECT_TRUE(v.is_type()); v = (int16_t) 2023; EXPECT_TRUE(v.is_type()); @@ -279,7 +280,7 @@ TEST(variant, is_type) TEST(variant, try_unwrap) { variant v; - EXPECT_FALSE(v.try_unwrap()); + EXPECT_TRUE(v.try_unwrap()); v = (int16_t) 5252; ASSERT_TRUE(v.try_unwrap()); EXPECT_EQ(5252, *v.try_unwrap()); @@ -290,7 +291,7 @@ TEST(variant, try_unwrap) TEST(variant, unwrap) { variant v; - EXPECT_THROW(v.unwrap(), std::runtime_error); + EXPECT_EQ(0, v.unwrap()); v = (int16_t) 5252; EXPECT_EQ(5252, v.unwrap()); EXPECT_THROW(v.unwrap(), std::runtime_error); @@ -321,35 +322,55 @@ TEST(variant, index) variant v; EXPECT_EQ(0, v.index()); v = (int8_t) 7; - EXPECT_EQ(1, v.index()); + EXPECT_EQ(0, v.index()); v = (uint8_t) 7; - EXPECT_EQ(2, v.index()); + EXPECT_EQ(1, v.index()); v = (int16_t) 7; - EXPECT_EQ(3, v.index()); + EXPECT_EQ(2, v.index()); v = (uint16_t) 7; - EXPECT_EQ(4, v.index()); + EXPECT_EQ(3, v.index()); v = "verifiable variant vying for vengence versus visa"; - EXPECT_EQ(5, v.index()); + EXPECT_EQ(4, v.index()); + + optional_variant vo; + EXPECT_EQ(0, vo.index()); + vo = (int8_t) 7; + EXPECT_EQ(1, vo.index()); + vo = (uint8_t) 7; + EXPECT_EQ(2, vo.index()); + vo = (int16_t) 7; + EXPECT_EQ(3, vo.index()); + vo = (uint16_t) 7; + EXPECT_EQ(4, vo.index()); + vo = "verifiable variant vying for vengence versus visa"; + EXPECT_EQ(5, vo.index()); } //------------------------------------------------------------------------------------------------------------------- TEST(variant, type_index_of) { variant v; - EXPECT_EQ(0, decltype(v)::type_index_of()); - EXPECT_EQ(1, decltype(v)::type_index_of()); - EXPECT_EQ(2, decltype(v)::type_index_of()); - EXPECT_EQ(3, decltype(v)::type_index_of()); - EXPECT_EQ(4, decltype(v)::type_index_of()); - EXPECT_EQ(5, decltype(v)::type_index_of()); + EXPECT_EQ(0, decltype(v)::type_index_of()); + EXPECT_EQ(1, decltype(v)::type_index_of()); + EXPECT_EQ(2, decltype(v)::type_index_of()); + EXPECT_EQ(3, decltype(v)::type_index_of()); + EXPECT_EQ(4, decltype(v)::type_index_of()); + + optional_variant vo; + EXPECT_EQ(0, decltype(vo)::type_index_of()); + EXPECT_EQ(1, decltype(vo)::type_index_of()); + EXPECT_EQ(2, decltype(vo)::type_index_of()); + EXPECT_EQ(3, decltype(vo)::type_index_of()); + EXPECT_EQ(4, decltype(vo)::type_index_of()); + EXPECT_EQ(5, decltype(vo)::type_index_of()); } //------------------------------------------------------------------------------------------------------------------- TEST(variant, constexpr_type_index_of) { variant v; - constexpr int TINDEX0 = decltype(v)::type_index_of(); - EXPECT_EQ(0, TINDEX0); - constexpr int TINDEX5 = decltype(v)::type_index_of(); - EXPECT_EQ(5, TINDEX5); + constexpr int TINDEX2 = decltype(v)::type_index_of(); + EXPECT_EQ(2, TINDEX2); + constexpr int TINDEX4 = decltype(v)::type_index_of(); + EXPECT_EQ(4, TINDEX4); } //------------------------------------------------------------------------------------------------------------------- TEST(variant, same_type) @@ -362,7 +383,6 @@ TEST(variant, same_type) TEST(variant, visit) { variant v; - EXPECT_THROW(v.visit(test_stringify_visitor()), std::runtime_error); v = "Rev"; test_stringify_visitor::test_visitation(v, std::string("Rev")); @@ -484,7 +504,7 @@ TEST(variant, ad_hoc_recursion) struct left_t; struct right_t; - using twisty = variant, boost::recursive_wrapper>; + using twisty = optional_variant, boost::recursive_wrapper>; struct left_t {