#pragma once #include <stdexcept> using namespace std; class NullIndirectError : public runtime_error{ public: NullIndirectError(); NullIndirectError(const string &what_arg); NullIndirectError(const char *what_arg); }; template <typename T> class Indirect{ T *ptr; class Dummy{}; Indirect(Dummy); public: template <typename ...Args> Indirect(Args... args); Indirect(const Indirect &other); Indirect(Indirect &&other); ~Indirect(); Indirect<T>& operator=(const T &value); Indirect<T>& operator=(T &&value); Indirect<T>& operator=(const Indirect<T> &other); Indirect<T>& operator=(Indirect<T> &&other); bool isEmpty() const; T& operator*(); const T& operator*() const; static Indirect<T> makeEmpty(); }; template <typename T> Indirect<T>::Indirect(Dummy) :ptr(nullptr){} template <typename T> Indirect<T> Indirect<T>::makeEmpty(){ return Indirect<T>(Indirect::Dummy()); }; template <typename T> template <typename ...Args> Indirect<T>::Indirect(Args... args) :ptr(new T(args...)){} template <typename T> Indirect<T>::Indirect(const Indirect &other){ if(!other.ptr){ ptr=nullptr; } else { ptr=new T(*other.ptr); } } template <typename T> Indirect<T>::Indirect(Indirect &&other){ if(!other.ptr){ ptr=nullptr; } else { ptr=new T(move(*other.ptr)); other.ptr=nullptr; } } template <typename T> Indirect<T>::~Indirect(){ if(ptr){ delete ptr; } } template <typename T> Indirect<T>& Indirect<T>::operator=(const T &value){ if(!ptr){ ptr=new T(value); } else { *ptr=value; } return *this; } template <typename T> Indirect<T>& Indirect<T>::operator=(T &&value){ if(!ptr){ ptr=new T(value); } else { *ptr=value; } return *this; } template <typename T> Indirect<T>& Indirect<T>::operator=(const Indirect<T> &other){ if(ptr){ delete ptr; } if(!other.ptr){ ptr=nullptr; } else { ptr=new T(*other.ptr); } return *this; } template <typename T> Indirect<T>& Indirect<T>::operator=(Indirect<T> &&other){ if(ptr){ delete ptr; } if(!other.ptr){ ptr=nullptr; } else { ptr=new T(move(*other.ptr)); other.ptr=nullptr; } return *this; } template <typename T> bool Indirect<T>::isEmpty() const { return ptr!=nullptr; } template <typename T> T& Indirect<T>::operator*(){ if(!ptr){ throw NullIndirectError(); } return *ptr; } template <typename T> const T& Indirect<T>::operator*() const { if(!ptr){ throw NullIndirectError(); } return *ptr; }