/// \file // Range v3 library // // Copyright Eric Niebler 2015-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_UTILITY_ANY_HPP #define RANGES_V3_UTILITY_ANY_HPP #include #include #include #include #include #include #include RANGES_DIAGNOSTIC_PUSH RANGES_DIAGNOSTIC_IGNORE_DEPRECATED_DECLARATIONS namespace ranges { struct bad_any_cast : std::bad_cast { virtual const char * what() const noexcept override { return "bad any_cast"; } }; struct RANGES_DEPRECATED( "ranges::any will be going away in the not-too-distant future. " "We suggest you use std::any or boost::any instead (or simply steal " "this header and maintain it yourself).") any; template meta::if_c() || copyable, T> any_cast(any &); template meta::if_c() || copyable, T> any_cast(any const &); template meta::if_c() || copyable, T> any_cast(any &&); template T * any_cast(any *) noexcept; template T const * any_cast(any const *) noexcept; struct any { private: template friend meta::if_c() || (bool)copyable, T> any_cast(any &); template friend meta::if_c() || (bool)copyable, T> any_cast( any const &); template friend meta::if_c() || (bool)copyable, T> any_cast( any &&); template friend T * any_cast(any *) noexcept; template friend T const * any_cast(any const *) noexcept; struct interface { virtual ~interface() {} virtual interface * clone() const = 0; virtual std::type_info const & type() const noexcept = 0; }; template struct impl final : interface { private: T obj; public: impl() = default; impl(T o) : obj(std::move(o)) {} T & get() { return obj; } T const & get() const { return obj; } impl * clone() const override { return new impl{obj}; } std::type_info const & type() const noexcept override { return typeid(T); } }; std::unique_ptr ptr_; public: any() noexcept = default; template> CPP_ctor(any)(TRef && t)( // requires copyable && (!same_as)) : ptr_(new impl(static_cast(t))) {} any(any &&) noexcept = default; any(any const & that) : ptr_{that.ptr_ ? that.ptr_->clone() : nullptr} {} any & operator=(any &&) noexcept = default; any & operator=(any const & that) { ptr_.reset(that.ptr_ ? that.ptr_->clone() : nullptr); return *this; } template> auto operator=(TRef && t) -> CPP_ret(any &)( // requires copyable && (!same_as)) { any{static_cast(t)}.swap(*this); return *this; } void clear() noexcept { ptr_.reset(); } bool empty() const noexcept { return !ptr_; } std::type_info const & type() const noexcept { return ptr_ ? ptr_->type() : typeid(void); } void swap(any & that) noexcept { ptr_.swap(that.ptr_); } #if !RANGES_BROKEN_CPO_LOOKUP friend void swap(any & x, any & y) noexcept { x.swap(y); } #endif }; #if RANGES_BROKEN_CPO_LOOKUP namespace _any_ { inline void swap(any & x, any & y) noexcept { x.swap(y); } } // namespace _any_ #endif /// \throw bad_any_cast template meta::if_c() || copyable, T> any_cast(any & x) { if(x.type() != typeid(detail::decay_t)) throw bad_any_cast{}; return static_cast> *>(x.ptr_.get())->get(); } /// \overload template meta::if_c() || copyable, T> any_cast(any const & x) { if(x.type() != typeid(detail::decay_t)) throw bad_any_cast{}; return static_cast> const *>(x.ptr_.get())->get(); } /// \overload template meta::if_c() || copyable, T> any_cast(any && x) { if(x.type() != typeid(detail::decay_t)) throw bad_any_cast{}; return static_cast> *>(x.ptr_.get())->get(); } /// \overload template T * any_cast(any * p) noexcept { if(p && p->ptr_) if(any::impl * q = dynamic_cast *>(p->ptr_.get())) return &q->get(); return nullptr; } /// \overload template T const * any_cast(any const * p) noexcept { if(p && p->ptr_) if(any::impl const * q = dynamic_cast const *>(p->ptr_.get())) return &q->get(); return nullptr; } } // namespace ranges RANGES_DIAGNOSTIC_POP #endif