#ifndef VARIANT_HPP #define VARIANT_HPP #include #include #include #include // pour std::enable_if et std::is_void #include // pour std::forward et std::move template struct _variant_element { //******************************* CONSTRUCTEURS ******************************// _variant_element() = default; _variant_element(Element const& x) : m_element(x) {} _variant_element(Element&& x) : m_element(std::move(x)) {} //******************************** OPÉRATEURS ********************************// _variant_element& operator = (Element const& x) { m_element = x; return *this; } _variant_element& operator = (Element&& x) { m_element = std::move(x); return *this; } //******************************** ACCESSEURS ********************************// Element& get() noexcept { return m_element; } Element const& get() const noexcept { return m_element; } void get(Element& x) const { x = m_element; } //********************************* MUTATEURS ********************************// template void set(Args&&... args) { operator=( Element(std::forward(args)...) ); } void set(_variant_element const& v) { operator=(v); } void set(_variant_element&& v) { operator=(std::move(v)); } //************************* AUTRES FONCTIONS MEMBRES *************************// std::type_info const& type_id() const noexcept { return typeid(Element); } template std::basic_istream& get(std::basic_istream& is) { return is >> m_element; } template std::basic_ostream& put(std::basic_ostream& os) const { return os << m_element; } //***************************** VARIABLES MEMBRES ****************************// private: Element m_element; }; // struct _variant_element template struct _variant_impl; template struct _variant_impl { //********************************* MUTATEURS ********************************// template ::value>::type> void set(std::size_t&) { index = N; } template ::type> void set(std::size_t&, _variant_impl const&) { index = N; } template ::type> void set(std::size_t&, _variant_impl&&) { index = N; } //************************* AUTRES FONCTIONS MEMBRES *************************// template ::type> bool empty() const noexcept { return true; } template inline bool type() const noexcept; template ::type> std::type_info const& type_id() const noexcept { return typeid(void); } template ::value>::type> inline std::basic_istream& get(std::size_t&, std::basic_istream&); template ::type> std::basic_ostream& put(std::basic_ostream& os) const { return os; } //************************ FONCTIONS MEMBRES STATIQUES ***********************// protected: template ::value>::type> static std::size_t index() noexcept { return N; } }; // struct _variant_impl //************************* AUTRES FONCTIONS MEMBRES *************************// template template inline bool _variant_impl::type() const noexcept { return false; } template template <> inline bool _variant_impl::type() const noexcept { return true; } template template inline std::basic_istream& _variant_impl::get(std::size_t& index, std::basic_istream& is) { index = N; return is; } template struct _variant_impl : public _variant_impl, private _variant_element::value, Element >::type> { //****************************** TYPES INTERNES ******************************// typedef _variant_impl _impl; typedef _variant_element _base; //******************************* CONSTRUCTEURS ******************************// _variant_impl() = default; template inline _variant_impl(T const&); template inline _variant_impl(T&&); //******************************** ACCESSEURS ********************************// template inline T& get() noexcept; template inline T const& get() const noexcept; template inline void get(T& x) const; //********************************* MUTATEURS ********************************// template inline void set(std::size_t&, Args&&...); template inline void set(std::size_t&, T const&); template inline void set(std::size_t&, T&&); // template // void set(std::size_t&, _variant_impl const& v) // { return _impl::set(v); } // template // void set(std::size_t&, _variant_impl&& v) // { return _impl::set(std::move(v)); } template inline void set(std::size_t&, _variant_impl const&); template inline void set(std::size_t&, _variant_impl&&); //************************* AUTRES FONCTIONS MEMBRES *************************// template inline bool empty() const noexcept; template inline bool type() const noexcept; template inline std::type_info const& type_id() const noexcept; template inline std::basic_istream& get(std::basic_istream&, std::size_t&); template inline std::basic_ostream& put(std::basic_ostream&) const; //************************ FONCTIONS MEMBRES STATIQUES ***********************// protected: template static inline std::size_t index() noexcept; }; // struct _variant_impl //******************************* CONSTRUCTEURS ******************************// template template inline _variant_impl::_variant_impl(T const& x) : _impl(x), _base() {} template template <> inline _variant_impl::_variant_impl(Element const& x) : _impl(), _base(x) {} template template inline _variant_impl::_variant_impl(T&& x) : _impl(std::move(x)), _base() {} template template <> inline _variant_impl::_variant_impl(Element&& x) : _impl(), _base(std::move(x)) {} //******************************** ACCESSEURS ********************************// template template inline T& _variant_impl::get() noexcept { return _impl::get(); } template template <> inline Element& _variant_impl::get/**/() noexcept { return _base::get(); } template template inline T const& _variant_impl::get() const noexcept { return _impl::get(); } template template <> inline Element _variant_impl::const& get/**/() const noexcept { return _base::get(); } template template inline void _variant_impl::get(T& x) const { return _impl::get(x); } template template <> void _variant_impl::get(Element& x) const inline { return _base::get(x); } //********************************* MUTATEURS ********************************// template template inline void _variant_impl::set(std::size_t& index, Args&&... args) { return _impl::set(index, std::forward(args)...); } template template inline void _variant_impl::set(std::size_t& index, Args&&... args) { _base::set(std::forward(args)...); index = Index; } template template inline void _variant_impl::set(std::size_t& index, T const& x) { return _impl::set(index, x); } template template <> inline void _variant_impl::set(std::size_t& index, Element const& x) { _base::set(x); index = Index; } template template inline void _variant_impl::set(std::size_t& index, T&& x) { return _impl::set(index, std::move(x)); } template template <> inline void _variant_impl::set(std::size_t& index, Element&& x) { _base::set(std::move(x)); index = Index; } //template //template //inline //void _variant_impl::set(std::size_t& index, _variant_impl const& v) //{ // return _impl::set(v); //} //template //template //inline //void _variant_impl::set(std::size_t& index, _variant_impl&& v) //{ // return _impl::set(std::move(v)); //} //template //template //inline //void _variant_impl::set(std::size_t& index, _variant_impl const& v) //{ // return set(v); //} //template //template //inline //void _variant_impl::set(std::size_t& index, _variant_impl&& v) //{ // return set(std::move(v)); //} //template //template <> //inline //void _variant_impl::set(std::size_t& index, _variant_impl const& v) //{ // _base::set(v._base::get()); // index = Index; //} //template //template <> //inline //void _variant_impl::set(std::size_t& index, _variant_impl&& v) //{ // _base::set( std::move(v._base::get()) ); // index = Index; //} template template inline void _variant_impl::set(std::size_t& index, _variant_impl const& v) { return _impl::set(index, v); } template template <> inline void _variant_impl::set(std::size_t& index, _variant_impl const& v) { _base::operator=(v); index = Index; } template template inline void _variant_impl::set(std::size_t& index, _variant_impl&&) { return _impl::set(index, std::move(v)); } template template <> inline void _variant_impl::set(std::size_t& index, _variant_impl&&) { _base::operator=(std::move(v)); index = Index; } //************************* AUTRES FONCTIONS MEMBRES *************************// template template inline bool _variant_impl::empty() const noexcept { return _impl::empty(); } template template <> inline bool _variant_impl::empty() const noexcept { return false; } template template inline bool _variant_impl::type() const noexcept { return _impl::type(); } template template inline bool _variant_impl::type() const noexcept { return false; } template template inline bool _variant_impl::type() const noexcept { return false; } template template <> inline bool _variant_impl::type() const noexcept { return true; } template template inline std::type_info const& _variant_impl::type_id() const noexcept { return _impl::type_id(); } template template <> inline std::type_info const& _variant_impl::type_id() const noexcept { return _base::type_id(); } template template inline std::basic_istream& _variant_impl::get(std::basic_istream& is, std::size_t& index) { return _impl::get(is, index); } template template inline std::basic_istream& _variant_impl::get(std::basic_istream& is, std::size_t& index) { _base::get(is); index = Index; return is; } template template inline std::basic_ostream& _variant_impl::put(std::basic_ostream& os) const { return _impl::put(os); } template template inline std::basic_ostream& _variant_impl::put(std::basic_ostream& os) const { return _base::put(os); } //************************ FONCTIONS MEMBRES STATIQUES ***********************// template template static std::size_t _variant_impl::index() noexcept { return _impl::index(); } template template <> inline std::size_t _variant_impl::index() noexcept { return Index; } template class variant : public _variant_impl<0, Elements...> { //****************************** TYPES INTERNES ******************************// private: typedef _variant_impl<0, Elements...> _base; //***************************** VARIABLES MEMBRES ****************************// private: std::size_t m_index; //******************************* CONSTRUCTEURS ******************************// public: variant() : _base(), m_index(_base::index()) {} template variant(T const& x) : _base(x), m_index(_base::index()) {} template variant(T&& x) : _base(std::move(x)), m_index(_base::index()) {} variant(variant const&) = default; variant(variant&&) = default; //******************************** DESTRUCTEUR *******************************// ~variant() = default; //******************************** OPÉRATEURS ********************************// template variant& operator = (T const& x) { set(x); return *this; } template variant& operator = (T&& x) { set(std::move(x)); return *this; } variant& operator = (variant const&) = default; variant& operator = (variant&&) = default; template operator T& () noexcept { return get(); } template operator T const& () const noexcept { return get(); } //******************************** ACCESSEURS ********************************// template T& get() noexcept { return _base::get(); } template T const& get() const noexcept { return _base::get(); } template void get(T& x) const { return _base::get(x); } //********************************* MUTATEURS ********************************// template void set(Args&&... args) { return _base::set(m_index, std::forward(args)...); } template void set(T const& x) { return _base::set(m_index, x); } template void set(T&& x) { return _base::set(m_index, std::move(x)); } // template // void set(variant const& v) // { return _base::set(v); } // template // void set(variant&& v) // { return _base::set(std::move(v)); } void set(variant const& v) { return _base::set(m_index, v); } void set(variant&& v) { return _base::set(m_index, std::move(v)); } //************************* AUTRES FONCTIONS MEMBRES *************************// bool empty() const noexcept { return _base::empty(); } template bool type() const noexcept { return _base::type(); } std::type_info const& type_id() const noexcept { return _base::type_id(); } template std::basic_istream& get(std::basic_istream& is) { return _base::get(m_index, is); } template std::basic_ostream& put(std::basic_ostream& os) const { return _base::put(os); } }; // class variant //********************************* MUTATEURS ********************************// //template //template //inline //void variant::set(variant const& v) //{ // return _base::set(m_index, v); //} //template //template //inline //void variant::set(variant&& v) //{ // return _base::set(m_index, std::move(v)); //} //************************ FONCTIONS NON-MEMBRES LIÉES ***********************// // Opérateurs template inline std::basic_ostream& operator << (std::basic_ostream& os, variant const& v) { return v.put(os); } #endif // VARIANT_HPP