#pragma once #include namespace RenderD7{ class Parameter { private: using id = size_t; template struct type { static void id() { } }; template static id type_id() { return reinterpret_cast(&type::id); } template using decay = typename std::decay::type; template using none = typename std::enable_if::value>::type; struct base { virtual ~base() { } virtual bool is(id) const = 0; virtual base *copy() const = 0; } *p = nullptr; template struct data : base, std::tuple { using std::tuple::tuple; T &get() & { return std::get<0>(*this); } T const &get() const& { return std::get<0>(*this); } bool is(id i) const override { return i == type_id(); } base *copy() const override { return new data{get()}; } }; template T &stat() { return static_cast&>(*p).get(); } template T const &stat() const { return static_cast const&>(*p).get(); } template T &dyn() { return dynamic_cast&>(*p).get(); } template T const &dyn() const { return dynamic_cast const&>(*p).get(); } public: /** * @brief Default constructor */ Parameter() { } /** * @brief Destructs the Parameter */ ~Parameter() { delete p; } /** * @brief Copy constructor * @param s The Parameter to copy */ Parameter(Parameter &&s) : p{s.p} { s.p = nullptr; } /** * @brief Const copy constructor * @param s The Parameter to copy */ Parameter(Parameter const &s) : p{s.p->copy()} { } /** * @brief Initializes the Parameter with the given value * @param x The value to initialize the Parameter with */ template, typename = none> Parameter(T &&x) : p{new data{std::forward(x)}} { } /** * @brief Overloads the assignment operator * @param s The value to set the Parameter to */ Parameter &operator=(Parameter s) { swap(*this, s); return *this; } friend void swap(Parameter &s, Parameter &r) { std::swap(s.p, r.p); } /** * @brief Clears the Parameter */ void clear() { delete p; p = nullptr; } /** * @brief Checks whether the Parameter is the given type * @tparam T The type to check * @return Whether the Parameter has the given type or not */ template bool is() const { return p ? p->is(type_id()) : false; } /** * @brief Returns the value of the Parameter * @tparam T The type of the Parameter * @return The value of the Parameter * @warning If the type of the Parameter doesn't match the type of it's stored value, it will result in undefined behaviour. */ template T &get() & { return stat(); } }; }