#include template class PairOfOptionals { T* first; D* second; void copyFrom(const PairOfOptionals& other); void free(); public: PairOfOptionals(); PairOfOptionals(const T& leftData, const D& rightData); PairOfOptionals(const PairOfOptionals& other); PairOfOptionals& operator=(const PairOfOptionals& other); ~PairOfOptionals(); void setFirst(const T& firstData); void setSecond(const D& firstData); const T& getFirst() const; const D& getSecond() const; void removeFirst(); void removeSecond(); bool containsFirst() const; bool containsSecond() const; bool operator==(const PairOfOptionals& rhs) const; bool operator!=(const PairOfOptionals& rhs) const; }; template PairOfOptionals::PairOfOptionals() : first(nullptr), second(nullptr){} template PairOfOptionals::PairOfOptionals(const T& leftData, const D& rightData) : first(nullptr), second(nullptr) { setFirst(leftData); setSecond(rightData); } template PairOfOptionals::PairOfOptionals(const PairOfOptionals& other) { copyFrom(other); } template PairOfOptionals& PairOfOptionals::operator=(const PairOfOptionals& other) { if (this != &other) { free(); copyFrom(other); } return *this; } template PairOfOptionals::~PairOfOptionals() { free(); } template void PairOfOptionals::setFirst(const T& firstData) { delete first; first = new T(firstData); } template void PairOfOptionals::setSecond(const D& secondData) { delete second; second = new D(secondData); } template const T& PairOfOptionals::getFirst() const { if (!containsFirst()) throw std::logic_error("No first element"); return *first; } template const D& PairOfOptionals::getSecond() const { if (!containsSecond()) throw std::logic_error("No second element"); return *second; } template void PairOfOptionals::removeFirst() { delete first; first = nullptr; } template void PairOfOptionals::removeSecond() { delete second; second = nullptr; } template bool PairOfOptionals::containsFirst() const { return first != nullptr; } template bool PairOfOptionals::containsSecond() const { return second != nullptr; } template void PairOfOptionals::copyFrom(const PairOfOptionals& other) { first = new T(other.first); second = new D(other.second); } template void PairOfOptionals::free() { delete first, second; } template bool compareValues(const S* ptr1, const S* ptr2) { return (ptr1 == nullptr && ptr2 == nullptr) || (ptr1 != nullptr && ptr2 != nullptr && *ptr1 == *ptr2); } template bool PairOfOptionals::operator==(const PairOfOptionals& rhs) const { return compareValues(first, rhs.first) && compareValues(second, rhs.second); } template bool PairOfOptionals::operator!=(const PairOfOptionals& rhs) const { return !(*this == rhs); }