/** ** \file misc/variant.hh ** \brief Interface of misc::variant. ** ** misc::variant is a wrapper over std::variant that adds ** conversion operators to the original standard variant class. ** misc::variant is used just like std::variant, and you ** won't be disturbed when using it. **/ #pragma once #include namespace misc { // Defining some concepts sepecific to variants: // Type T can be converted into another type in Ts, // used to set the variant's value. template concept ContainsTypeSet = std::disjunction...>::value; // A type in Ts can be converted into T, used to get the variant's value. template concept ContainsTypeGet = std::disjunction...>::value; /// Type V is a visitor on each Ts. template concept Visits = std::conjunction...>::value; /// A wrapper over std::variant supporting conversion operators. /// /// Constraints: /// - No type may be const-qualified. /// - Each type must be unique. /// - The first type must be default constructible. /// /// Proper declaration form: /// misc::variant template class variant : public std::variant { public: /// The type of this variant. using self_type = variant; /// Super type. using super_type = std::variant; /// Constructors. /// \{ variant() = default; template requires ContainsTypeSet variant(const U& rhs); /// \} template requires ContainsTypeSet self_type& operator=(const U&); /// \brief Convert this variant to a value of type \a U. /// /// This conversion relies on std::get. In particular, if the /// conversion fails, a std::bad_variant_access exception is thrown. template requires ContainsTypeGet operator U&(); /// Likewise, const version. template requires ContainsTypeGet operator const U&() const; /** \brief Visit variants of this class. ** std::visit does not handle classes inheriting from std::variant, hence ** these wrappers. ** \{ */ template requires Visits auto visit(V&& visitor) const; template static auto visit(V&& visitor, Variants&&... vars); /** \} */ }; // Here add variadic template recursion on std::get template std::ostream& operator<<(std::ostream& os, const variant& obj); class PrintVisitor { public: PrintVisitor(std::ostream& os) : os_(os) {} template std::ostream& operator()(const T& value) const; private: std::ostream& os_; }; } // namespace misc #include