diff options
Diffstat (limited to 'tiger-compiler/lib/misc/variant.hh')
| -rw-r--r-- | tiger-compiler/lib/misc/variant.hh | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/tiger-compiler/lib/misc/variant.hh b/tiger-compiler/lib/misc/variant.hh new file mode 100644 index 0000000..71a8c1a --- /dev/null +++ b/tiger-compiler/lib/misc/variant.hh @@ -0,0 +1,111 @@ +/** + ** \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 <variant> + +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 <typename T, typename... Ts> + concept ContainsTypeSet = + std::disjunction<std::is_convertible<T, Ts>...>::value; + + // A type in Ts can be converted into T, used to get the variant's value. + template <typename T, typename... Ts> + concept ContainsTypeGet = + std::disjunction<std::is_convertible<Ts, T>...>::value; + + /// Type V is a visitor on each Ts. + template <typename V, typename... Ts> + concept Visits = std::conjunction<std::is_invocable<V, Ts>...>::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<T, T1, ..., Tn> + + template <typename T, typename... Ts> + class variant : public std::variant<T, Ts...> + { + public: + /// The type of this variant. + using self_type = variant<T, Ts...>; + /// Super type. + + using super_type = std::variant<T, Ts...>; + + /// Constructors. + /// \{ + variant() = default; + + template <typename U> + requires ContainsTypeSet<U, T, Ts...> + variant(const U& rhs); + /// \} + + template <typename U> + requires ContainsTypeSet<U, T, Ts...> + 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 <typename U> + requires ContainsTypeGet<U, T, Ts...> + operator U&(); + + /// Likewise, const version. + template <typename U> + requires ContainsTypeGet<U, T, Ts...> + operator const U&() const; + + /** \brief Visit variants of this class. + ** std::visit does not handle classes inheriting from std::variant, hence + ** these wrappers. + ** \{ */ + template <typename V> + requires Visits<V, T, Ts...> + auto visit(V&& visitor) const; + + template <typename V, class... Variants> + static auto visit(V&& visitor, Variants&&... vars); + /** \} */ + }; + + // Here add variadic template recursion on std::get + template <typename T, typename... Ts> + std::ostream& operator<<(std::ostream& os, const variant<T, Ts...>& obj); + + class PrintVisitor + { + public: + PrintVisitor(std::ostream& os) + : os_(os) + {} + + template <typename T> std::ostream& operator()(const T& value) const; + + private: + std::ostream& os_; + }; +} // namespace misc + +#include <misc/variant.hxx> |
