#include #include #include #include #include #include #include /* Given helper functions */ template T* retrieve(char* memory) { return std::launder(reinterpret_cast(memory)); } void empty_dtor(char*) { } template void default_dtor(char* memory) { auto object = retrieve(memory); std::destroy_at(object); } /* Write Bounded_Any here */ template class Bounded_Any { public: Bounded_Any() = default; Bounded_Any(Bounded_Any const& other) = delete; ~Bounded_Any() { clear(); } Bounded_Any& operator=(Bounded_Any const& other) = delete; template Bounded_Any& operator=(T const& data) { if constexpr (sizeof(T) > N) throw std::invalid_argument { "Object too big" }; else { // destroy previous element (*dtor)(memory); new (memory) T { data }; type = typeid(T); dtor = &default_dtor; return *this; } } template T& get() { if (typeid(T) == type) return *retrieve(memory); throw std::invalid_argument { "Incorrect type" }; } void clear() { (*dtor)(memory); dtor = &empty_dtor; type = typeid(void); } template bool has_type() const { return typeid(T) == type; } bool has_value() const { return !has_type(); } private: char memory[N]; std::type_index type { typeid(void) }; void (*dtor)(char*) { &empty_dtor }; }; /* Testcases */ int main() { // Make sure that we can create an empty Bounded_Any Bounded_Any<4> a1 { }; assert( !a1.has_value() ); // Make a1 an integer a1 = 5; assert( a1.has_type() ); assert( a1.get() == 5 ); // Try to assign it something that is larger than // what can be fit in the bounded any try { a1 = 5.0; assert( false ); } catch (...) { } // Make sure the error didn't change the currently stored data assert( a1.has_type() ); assert( a1.get() == 5 ); // Create a new block to test that destruction works properly { Bounded_Any<100> a2 { }; // Set the bounded any to a LARGE string (as to force allocations) a2 = std::string(1024, '+'); assert( a2.has_type() ); assert( a2.get() == std::string(1024, '+') ); // Clear the data (which should result in the string destructor being called) a2.clear(); assert( !a2.has_type() ); assert( !a2.has_value() ); // Insert a large vector instead, and make sure that the destructor of // Bounded_Any properly calls the std::vector destructor. a2 = std::vector(2048, 1); assert( a2.has_type>() ); assert( a2.get>() == std::vector(2048, 1) ); } a1.clear(); // Make sure clearing resets the any to its default state assert( !a1.has_type() ); assert( !a1.has_value() ); }