diff --git a/module-1/homework/Variant/tests.cpp b/module-1/homework/Variant/tests.cpp index 3075960e..df9fda53 100644 --- a/module-1/homework/Variant/tests.cpp +++ b/module-1/homework/Variant/tests.cpp @@ -6,25 +6,34 @@ #include "gtest/gtest.h" TEST(Get, Test1) { - task::variant v; + variant v; + //v = std::string("Hello world"); + v = "Hello world"; - ASSERT_EQ(std::get(v),"Hello world"); + ASSERT_EQ(get(v),"Hello world"); +} + +TEST(Get, Test1_1) { + variant v; + v = std::string("Hello world"); + ASSERT_EQ(get(v),"Hello world"); } TEST(Get, Test2) { - task::variant v; + variant v; v = 12.0; - ASSERT_NEAR(std::get(v), 12.0, 1e-5); + ASSERT_NEAR(get(v), 12.0, 1e-5); } + TEST(Get, Test3) { - task::variant v; + variant v; v = "Hello world"; - ASSERT_EQ(std::get<2>(v), "Hello world"); + ASSERT_EQ(get<2>(v), "Hello world"); } TEST(Get, Test4) { - task::variant v; + variant v; v = 12.0; - ASSERT_NEAR(std::get<1>(v), 12.0, 1e-5); + ASSERT_NEAR(get<1>(v), 12.0, 1e-5); } \ No newline at end of file diff --git a/module-1/homework/Variant/variant.h b/module-1/homework/Variant/variant.h index 428e1966..1ed7fc30 100644 --- a/module-1/homework/Variant/variant.h +++ b/module-1/homework/Variant/variant.h @@ -1,8 +1,76 @@ #include +#include #pragma once -namespace task { +template +auto test_implicitly_convertible(int) -> decltype( + void(std::declval()(std::declval())), std::true_type{} +); + +template +auto test_implicitly_convertible(...) -> std::false_type; + +template +struct is_implicitly_convertible : std::integral_constant(0))::value> {}; + +template +union __union; + +template +union __union { + +}; + +struct __union_helper { + template + static constexpr auto&& get(U&& v, std::in_place_index_t<0>) { + return std::forward(v).head; + } + + template + static constexpr auto&& get(U&& v, std::in_place_index_t) { + return get(std::forward(v).tail, std::in_place_index); + } + + template + static void set(U&& value, std::in_place_index_t<0>, __union& u) { + if (std::is_same_v) { + u.head = value; + } else if (is_implicitly_convertible::value) { + u.head = value; + } + } + + template + static void set(U&& value, std::in_place_index_t, __union& u) { + set(std::forward(value), std::in_place_index, u.tail); + } +}; + + +template +union __union { +public: + + T head; + __union tail; + + __union() { + if (!std::is_trivially_constructible_v) { + head = T(); + } + } + + ~__union() { + if (!std::is_trivially_destructible_v) { + head.~T(); + } + } + + friend struct __union_helper; +}; template class variant; @@ -13,37 +81,114 @@ struct variant_alternative; template using variant_alternative_t = typename variant_alternative::type; -template -struct variant_alternative> { - using type = // Your code goes here +static constexpr int not_founded = -1; + + +template +constexpr std::size_t find_type_pos( + std::size_t cur_pos, + const bool (&founded)[SizeofFounded], + const bool (&constr)[SizeofFounded] + ) { + return (cur_pos == SizeofFounded) ? not_founded : + ((founded[cur_pos] || constr[cur_pos]) ? cur_pos : find_type_pos(cur_pos + 1, founded, constr)); +} + +template +constexpr std::size_t find_type_pos( + std::size_t cur_pos, + const bool (&founded)[SizeofFounded] +) { + return (cur_pos == SizeofFounded) ? not_founded : + ((founded[cur_pos]) ? cur_pos : find_type_pos(cur_pos + 1, founded)); +} + +template +struct find_exactly_one_checked_ { + constexpr static bool founded[sizeof...(Types)] = {std::is_same::value...}; + constexpr static bool constructible[sizeof...(Types)] = {is_implicitly_convertible::value...}; + constexpr static std::size_t valueForAssignment = find_type_pos(0, founded) == -1 ? find_type_pos(0, founded, constructible) : find_type_pos(0, founded);//find_type_pos(0, founded); + constexpr static std::size_t value = find_type_pos(0, founded);//find_type_pos(0, founded); }; +template +struct find_exactly_one_t : public find_exactly_one_checked_ {}; + +template +struct Typelist{ + typedef head Head; + typedef Typelist Tail; +}; + +template struct TypeAt; + +template +struct TypeAt<0, Typelist> { + typedef Head Result; +}; +template +struct TypeAt> { + typedef typename TypeAt>::Result Result; +}; + +template +struct variant_alternative> { + using type = typename TypeAt>::Result;// Your code goes here +}; + + +template +auto&& generic_get(variant& v) { + return __union_helper::get(std::forward>(v).data_, std::in_place_index::value>); +} + template class variant { - - public: +public: // Special member functions constexpr variant() noexcept; template variant& operator=( T&& t ) noexcept; - - private: + + template friend + auto&& generic_get(variant& v); +private: // Your code goes here + __union<0, Types...> data_; }; +template +template +variant& variant::operator=(T&& t) noexcept { + constexpr auto value = find_exactly_one_t::valueForAssignment; + static_assert(value != -1); + __union_helper::set(std::forward(t), std::in_place_index, this->data_); + return *this; +} + +template +constexpr variant::variant() noexcept {}; + + // Non-member functions template -constexpr variant_alternative_t>& get(variant& v); +constexpr const variant_alternative_t>& get(variant& v) { + return generic_get>::Result>(std::forward(v)); +} template -constexpr variant_alternative_t>&& get(variant&& v); +constexpr variant_alternative_t>&& get(variant&& v) { + return generic_get>::Result>(std::move(v)); +} template -constexpr T& get(variant& v); +constexpr const T& get(variant& v) { + return generic_get(v); +} template -constexpr T&& get( variant&& v ); - -}; \ No newline at end of file +constexpr T&& get( variant&& v ) { + return generic_get(std::move(v)); +}